www.gusucode.com > VC++ 车牌定位与识别源码程序 > VC++ 车牌定位与识别源码程序/code/PlateReco/GlobalFunction.cpp
//Download by http://www.NewXing.com /************************************************************************** * 文件名:GlobalFunction.cpp * * 图像处理API函数库: * * LinerTrans() - 图像线性变换 * WindowTrans() - 图像窗口变换 * GrayStretch() - 图像灰度拉伸 * InteEqualize() -直方图均衡 * ZoomDIB() - 图像缩放 * RotateDIB() - 图像旋转 * ErosionDIB() - 图像腐蚀 * DilationDIB() - 图像膨胀 * OpenDIB() - 图像开运算 * CloseDIB() - 图像闭运算 * ThiningDIB() - 图像细化 * RobertDIB() - robert边缘检测运算 * SobelDIB() - sobel边缘检测运算 * PrewittDIB() - prewitt边缘检测运算 * KirschDIB() - kirsch边缘检测运算 * GaussDIB() - gauss边缘检测运算 * * Template() - 图像模板变换,通过改变模板,可以用它实现 * 图像的平滑、锐化、边缘识别等操作。 * MedianFilter() - 图像中值滤波。 * GetMedianNum() - 获取中值。被函数MedianFilter()调用来求中值。 * * RowScanDIB() - 基于行扫描的车牌提取 * CharacterUnit() - 字符归一化 * * BpTrain() - BP网络训练 * BpReco() - BP网络识别 * * ContourDIB() - 轮廓提取 * TraceDIB() - 轮廓跟踪 * * FFT() - 快速付立叶变换 * IFFT() - 快速付立叶反变换 * DCT() - 离散余弦变换 * WALSH() - 沃尔什-哈达玛变换 * * Fourier() - 图像的付立叶变换 * DIBDct() - 图像的离散余弦变换 * DIBWalsh() - 图像的沃尔什-哈达玛变换 * * ThresholdDIB() - 图像阈值分割运算 * AddMinusDIB() - 图像加减运算 * HprojectDIB() - 图像水平投影 * VprojectDIB() - 图像垂直投影 * TemplateDIB() - 图像模板匹配运算 * * Distance13() - 计算距离图像点最近的段 * CharExtract13Sect() - 13段投影法特征提取 * DistanceStruct() - 微结构特征提取法中求待识字符 - 特征向量与字典中各特征向量间 - 的最小距离 *************************************************************************/ #include "stdafx.h" #include "Dibapi.h" #include <math.h> #include <direct.h> /************************************************************************* * * 函数名称: * LinerTrans() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * FLOAT fA - 线性变换的斜率 * FLOAT fB - 线性变换的截距 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行灰度的线性变换操作。 * ************************************************************************/ BOOL WINAPI LinerTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, FLOAT fA, FLOAT fB) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 图像每行的字节数 LONG lLineBytes; // 中间变量 FLOAT fTemp; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 每行 for(i = 0; i < lHeight; i++) { // 每列 for(j = 0; j < lWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 线性变换 fTemp = fA * (*lpSrc) + fB; // 判断是否超出范围 if (fTemp > 255) { // 直接赋值为255 *lpSrc = 255; } else if (fTemp < 0) { // 直接赋值为0 *lpSrc = 0; } else { // 四舍五入 *lpSrc = (unsigned char) (fTemp + 0.5); } } } // 返回 return TRUE; } /************************************************************************* * * 函数名称: * ThresholdTrans() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * BYTE bThre - 阈值 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行阈值变换。对于灰度值小于阈值的象素直接设置 * 灰度值为0;灰度值大于阈值的象素直接设置为255。 * ************************************************************************/ BOOL WINAPI ThresholdTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bThre) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 每行 for(i = 0; i < lHeight; i++) { // 每列 for(j = 0; j < lWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 判断是否小于阈值 if ((*lpSrc) < bThre) { // 直接赋值为0 *lpSrc = 0; } else { // 直接赋值为255 *lpSrc = 255; } } } // 返回 return TRUE; } /************************************************************************* * * 函数名称: * WindowTrans() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * BYTE bLow - 窗口下限 * BYTE bUp - 窗口上限 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行窗口变换。只有在窗口范围内的灰度保持不变, * 小于下限的象素直接设置灰度值为0;大于上限的象素直接设置灰度值为255。 * ************************************************************************/ BOOL WINAPI WindowTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bLow, BYTE bUp) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 每行 for(i = 0; i < lHeight; i++) { // 每列 for(j = 0; j < lWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 判断是否超出范围 if ((*lpSrc) < bLow) { // 直接赋值为0 *lpSrc = 0; } else if ((*lpSrc) > bUp) { // 直接赋值为255 *lpSrc = 255; } } } // 返回 return TRUE; } /************************************************************************* * * 函数名称: * GrayStretch() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * BYTE bX1 - 灰度拉伸第一个点的X坐标 * BYTE bY1 - 灰度拉伸第一个点的Y坐标 * BYTE bX2 - 灰度拉伸第二个点的X坐标 * BYTE bY2 - 灰度拉伸第二个点的Y坐标 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行灰度拉伸。 * ************************************************************************/ BOOL WINAPI GrayStretch(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bX1, BYTE bY1, BYTE bX2, BYTE bY2) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 灰度映射表 BYTE bMap[256]; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 计算灰度映射表 for (i = 0; i <= bX1; i++) { // 判断bX1是否大于0(防止分母为0) if (bX1 > 0) { // 线性变换 bMap[i] = (BYTE) bY1 * i / bX1; } else { // 直接赋值为0 bMap[i] = 0; } } for (; i <= bX2; i++) { // 判断bX1是否等于bX2(防止分母为0) if (bX2 != bX1) { // 线性变换 bMap[i] = bY1 + (BYTE) ((bY2 - bY1) * (i - bX1) / (bX2 - bX1)); } else { // 直接赋值为bY1 bMap[i] = bY1; } } for (; i < 256; i++) { // 判断bX2是否等于255(防止分母为0) if (bX2 != 255) { // 线性变换 bMap[i] = bY2 + (BYTE) ((255 - bY2) * (i - bX2) / (255 - bX2)); } else { // 直接赋值为255 bMap[i] = 255; } } // 每行 for(i = 0; i < lHeight; i++) { // 每列 for(j = 0; j < lWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 计算新的灰度值 *lpSrc = bMap[*lpSrc]; } } // 返回 return TRUE; } /************************************************************************* * * 函数名称: * InteEqualize() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行直方图均衡。 * ************************************************************************/ BOOL WINAPI InteEqualize(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; // 临时变量 LONG lTemp; // 循环变量 LONG i; LONG j; // 灰度映射表 BYTE bMap[256]; // 灰度映射表 LONG lCount[256]; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 重置计数为0 for (i = 0; i < 256; i ++) { // 清零 lCount[i] = 0; } // 计算各个灰度值的计数 for (i = 0; i < lHeight; i ++) { for (j = 0; j < lWidth; j ++) { lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; // 计数加1 lCount[*(lpSrc)]++; } } // 计算灰度映射表 for (i = 0; i < 256; i++) { // 初始为0 lTemp = 0; for (j = 0; j <= i ; j++) { lTemp += lCount[j]; } // 计算对应的新灰度值 bMap[i] = (BYTE) (lTemp * 255 / lHeight / lWidth); } // 每行 for(i = 0; i < lHeight; i++) { // 每列 for(j = 0; j < lWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 计算新的灰度值 *lpSrc = bMap[*lpSrc]; } } // 返回 return TRUE; } /************************************************************************* * * 函数名称: * ZoomDIB() * * 参数: * LPSTR lpDIB - 指向源DIB的指针 * float fXZoomRatio - X轴方向缩放比率 * float fYZoomRatio - Y轴方向缩放比率 * * 返回值: * HGLOBAL - 缩放成功返回新DIB句柄,否则返回NULL。 * * 说明: * 该函数用来缩放DIB图像,返回新生成DIB的句柄。 * ************************************************************************/ HGLOBAL WINAPI ZoomDIB(LPSTR lpDIB, float fXZoomRatio, float fYZoomRatio) { // 源图像的宽度和高度 LONG lWidth; LONG lHeight; // 缩放后图像的宽度和高度 LONG lNewWidth; LONG lNewHeight; // 缩放后图像的宽度(lNewWidth',必须是4的倍数) LONG lNewLineBytes; // 指向源图像的指针 LPSTR lpDIBBits; // 指向源象素的指针 LPSTR lpSrc; // 缩放后新DIB句柄 HDIB hDIB; // 指向缩放图像对应象素的指针 LPSTR lpDst; // 指向缩放图像的指针 LPSTR lpNewDIB; LPSTR lpNewDIBBits; // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFOHEADER lpbmi; // 指向BITMAPCOREINFO结构的指针 LPBITMAPCOREHEADER lpbmc; // 循环变量(象素在新DIB中的坐标) LONG i; LONG j; // 象素在源DIB中的坐标 LONG i0; LONG j0; // 图像每行的字节数 LONG lLineBytes; // 找到源DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 获取图像的宽度 lWidth = ::DIBWidth(lpDIB); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 获取图像的高度 lHeight = ::DIBHeight(lpDIB); // 计算缩放后的图像实际宽度 // 此处直接加0.5是由于强制类型转换时不四舍五入,而是直接截去小数部分 lNewWidth = (LONG) (::DIBWidth(lpDIB) * fXZoomRatio + 0.5); // 计算新图像每行的字节数 lNewLineBytes = WIDTHBYTES(lNewWidth * 8); // 计算缩放后的图像高度 lNewHeight = (LONG) (lHeight * fYZoomRatio + 0.5); // 分配内存,以保存新DIB hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); // 判断是否内存分配失败 if (hDIB == NULL) { // 分配内存失败 return NULL; } // 锁定内存 lpNewDIB = (char * )::GlobalLock((HGLOBAL) hDIB); // 复制DIB信息头和调色板 memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); // 找到新DIB象素起始位置 lpNewDIBBits = ::FindDIBBits(lpNewDIB); // 获取指针 lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; lpbmc = (LPBITMAPCOREHEADER)lpNewDIB; // 更新DIB中图像的高度和宽度 if (IS_WIN30_DIB(lpNewDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = lNewWidth; lpbmi->biHeight = lNewHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) lNewWidth; lpbmc->bcHeight = (unsigned short) lNewHeight; } // 针对图像每行进行操作 for(i = 0; i < lNewHeight; i++) { // 针对图像每列进行操作 for(j = 0; j < lNewWidth; j++) { // 指向新DIB第i行,第j个象素的指针 // 注意此处宽度和高度是新DIB的宽度和高度 lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i) + j; // 计算该象素在源DIB中的坐标 i0 = (LONG) (i / fYZoomRatio + 0.5); j0 = (LONG) (j / fXZoomRatio + 0.5); // 判断是否在源图范围内 if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight)) { // 指向源DIB第i0行,第j0个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight - 1 - i0) + j0; // 复制象素 *lpDst = *lpSrc; } else { // 对于源图中没有的象素,直接赋值为255 * ((unsigned char*)lpDst) = 255; } } } // 返回 return hDIB; } /************************************************************************* * * 函数名称: * RotateDIB() * * 参数: * LPSTR lpDIB - 指向源DIB的指针 * int iRotateAngle - 旋转的角度(0-360度) * * 返回值: * HGLOBAL - 旋转成功返回新DIB句柄,否则返回NULL。 * * 说明: * 该函数用来以图像中心为中心旋转DIB图像,返回新生成DIB的句柄。 * 调用该函数会自动扩大图像以显示所有的象素。函数中采用最邻近插 * 值算法进行插值。 * ************************************************************************/ HGLOBAL WINAPI RotateDIB(LPSTR lpDIB, int iRotateAngle) { // 源图像的宽度和高度 LONG lWidth; LONG lHeight; // 旋转后图像的宽度和高度 LONG lNewWidth; LONG lNewHeight; // 图像每行的字节数 LONG lLineBytes; // 旋转后图像的宽度(lNewWidth',必须是4的倍数) LONG lNewLineBytes; // 指向源图像的指针 LPSTR lpDIBBits; // 指向源象素的指针 LPSTR lpSrc; // 旋转后新DIB句柄 HDIB hDIB; // 指向旋转图像对应象素的指针 LPSTR lpDst; // 指向旋转图像的指针 LPSTR lpNewDIB; LPSTR lpNewDIBBits; // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFOHEADER lpbmi; // 指向BITMAPCOREINFO结构的指针 LPBITMAPCOREHEADER lpbmc; // 循环变量(象素在新DIB中的坐标) LONG i; LONG j; // 象素在源DIB中的坐标 LONG i0; LONG j0; // 旋转角度(弧度) float fRotateAngle; // 旋转角度的正弦和余弦 float fSina, fCosa; // 源图四个角的坐标(以图像中心为坐标系原点) float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4; // 旋转后四个角的坐标(以图像中心为坐标系原点) float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4; // 两个中间常量 float f1,f2; // 找到源DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 获取图像的"宽度"(4的倍数) lWidth = ::DIBWidth(lpDIB); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 获取图像的高度 lHeight = ::DIBHeight(lpDIB); // 将旋转角度从度转换到弧度 fRotateAngle = (float) RADIAN(iRotateAngle); // 计算旋转角度的正弦 fSina = (float) sin((double)fRotateAngle); // 计算旋转角度的余弦 fCosa = (float) cos((double)fRotateAngle); // 计算原图的四个角的坐标(以图像中心为坐标系原点) fSrcX1 = (float) (- (lWidth - 1) / 2); fSrcY1 = (float) ( (lHeight - 1) / 2); fSrcX2 = (float) ( (lWidth - 1) / 2); fSrcY2 = (float) ( (lHeight - 1) / 2); fSrcX3 = (float) (- (lWidth - 1) / 2); fSrcY3 = (float) (- (lHeight - 1) / 2); fSrcX4 = (float) ( (lWidth - 1) / 2); fSrcY4 = (float) (- (lHeight - 1) / 2); // 计算新图四个角的坐标(以图像中心为坐标系原点) fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1; fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1; fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2; fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2; fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3; fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3; fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4; fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4; // 计算旋转后的图像实际宽度 lNewWidth = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5); // 计算新图像每行的字节数 lNewLineBytes = WIDTHBYTES(lNewWidth * 8); // 计算旋转后的图像高度 lNewHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) + 0.5); // 两个常数,这样不用以后每次都计算了 f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina + 0.5 * (lWidth - 1)); f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa + 0.5 * (lHeight - 1)); // 分配内存,以保存新DIB hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); // 判断是否内存分配失败 if (hDIB == NULL) { // 分配内存失败 return NULL; } // 锁定内存 lpNewDIB = (char * )::GlobalLock((HGLOBAL) hDIB); // 复制DIB信息头和调色板 memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); // 找到新DIB象素起始位置 lpNewDIBBits = ::FindDIBBits(lpNewDIB); // 获取指针 lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; lpbmc = (LPBITMAPCOREHEADER)lpNewDIB; // 更新DIB中图像的高度和宽度 if (IS_WIN30_DIB(lpNewDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = lNewWidth; lpbmi->biHeight = lNewHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) lNewWidth; lpbmc->bcHeight = (unsigned short) lNewHeight; } // 针对图像每行进行操作 for(i = 0; i < lNewHeight; i++) { // 针对图像每列进行操作 for(j = 0; j < lNewWidth; j++) { // 指向新DIB第i行,第j个象素的指针 // 注意此处宽度和高度是新DIB的宽度和高度 lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i) + j; // 计算该象素在源DIB中的坐标 i0 = (LONG) (-((float) j) * fSina + ((float) i) * fCosa + f2 + 0.5); j0 = (LONG) ( ((float) j) * fCosa + ((float) i) * fSina + f1 + 0.5); // 判断是否在源图范围内 if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight)) { // 指向源DIB第i0行,第j0个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight - 1 - i0) + j0; // 复制象素 *lpDst = *lpSrc; } else { // 对于源图中没有的象素,直接赋值为255 * ((unsigned char*)lpDst) = 255; } } } // 返回 return hDIB; } /************************************************************************* * * 函数名称: * ErosiontionDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * int nMode - 腐蚀方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。 * int structure[3][3] - 自定义的3×3结构元素。 * * 返回值: * BOOL - 腐蚀成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行腐蚀运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点; * 或者由用户自己定义3×3的结构元素。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI ErosionDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3]) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; int n; int m; //像素值 unsigned char pixel; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); if(nMode == 0) { //使用水平方向的结构元素进行腐蚀 for(j = 0; j <lHeight; j++) { for(i = 1;i <lWidth-1; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成黑色 *lpDst = (unsigned char)0; //如果源图像中当前点自身或者左右有一个点不是黑色, //则将目标图像中的当前点赋成白色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+n-1); if (pixel == 255 ) { *lpDst = (unsigned char)255; break; } } } } } else if(nMode == 1) { //使用垂直方向的结构元素进行腐蚀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成黑色 *lpDst = (unsigned char)0; //如果源图像中当前点自身或者上下有一个点不是黑色, //则将目标图像中的当前点赋成白色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+(n-1)*lWidth); if (pixel == 255 ) { *lpDst = (unsigned char)255; break; } } } } } else { //使用自定义的结构元素进行腐蚀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 //和最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成黑色 *lpDst = (unsigned char)0; //如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色, //则将目标图像中的当前点赋成白色 //注意在DIB图像中内容是上下倒置的 for (m = 0;m < 3;m++ ) { for (n = 0;n < 3;n++) { if( structure[m][n] == -1) continue; pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1)); if (pixel == 255 ) { *lpDst = (unsigned char)255; break; } } } } } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * DilationDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * int nMode - 膨胀方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。 * int structure[3][3] - 自定义的3×3结构元素。 * * 返回值: * BOOL - 膨胀成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行膨胀运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点; * 或者由用户自己定义3×3的结构元素。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI DilationDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3]) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; int n; int m; //像素值 unsigned char pixel; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); if(nMode == 0) { //使用水平方向的结构元素进行膨胀 for(j = 0; j <lHeight; j++) { for(i = 1;i <lWidth-1; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && pixel != 0) return FALSE; //目标图像中的当前点先赋成白色 *lpDst = (unsigned char)255; //源图像中当前点自身或者左右只要有一个点是黑色, //则将目标图像中的当前点赋成黑色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+n-1); if (pixel == 0 ) { *lpDst = (unsigned char)0; break; } } } } } else if(nMode == 1) { //使用垂直方向的结构元素进行膨胀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成白色 *lpDst = (unsigned char)255; //源图像中当前点自身或者上下只要有一个点是黑色, //则将目标图像中的当前点赋成黑色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+(n-1)*lWidth); if (pixel == 0 ) { *lpDst = (unsigned char)0; break; } } } } } else { //使用自定义的结构元素进行膨胀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 //和最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成白色 *lpDst = (unsigned char)255; //原图像中对应结构元素中为黑色的那些点中只要有一个是黑色, //则将目标图像中的当前点赋成黑色 //注意在DIB图像中内容是上下倒置的 for (m = 0;m < 3;m++ ) { for (n = 0;n < 3;n++) { if( structure[m][n] == -1) continue; pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1)); if (pixel == 0 ) { *lpDst = (unsigned char)0; break; } } } } } } // 复制膨胀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * OpenDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * int nMode - 开运算方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。 * int structure[3][3] - 自定义的3×3结构元素。 * * 返回值: * BOOL - 开运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行开运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点; * 或者由用户自己定义3×3的结构元素。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI OpenDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3]) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; int n; int m; //像素值 unsigned char pixel; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); if(nMode == 0) { //使用水平方向的结构元素进行腐蚀 for(j = 0; j <lHeight; j++) { for(i = 1;i <lWidth-1; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成黑色 *lpDst = (unsigned char)0; //如果源图像中当前点自身或者左右有一个点不是黑色, //则将目标图像中的当前点赋成白色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+n-1); if (pixel == 255 ) { *lpDst = (unsigned char)255; break; } } } } } else if(nMode == 1) { //使用垂直方向的结构元素进行腐蚀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成黑色 *lpDst = (unsigned char)0; //如果源图像中当前点自身或者上下有一个点不是黑色, //则将目标图像中的当前点赋成白色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+(n-1)*lWidth); if (pixel == 255 ) { *lpDst = (unsigned char)255; break; } } } } } else { //使用自定义的结构元素进行腐蚀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 //和最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成黑色 *lpDst = (unsigned char)0; //如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色, //则将目标图像中的当前点赋成白色 //注意在DIB图像中内容是上下倒置的 for (m = 0;m < 3;m++ ) { for (n = 0;n < 3;n++) { if( structure[m][n] == -1) continue; pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1)); if (pixel == 255 ) { *lpDst = (unsigned char)255; break; } } } } } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 重新初始化新分配的内存,设定初始值为255 //lpDst = (char *)lpNewDIBBits; //memset(lpDst, (BYTE)255, lWidth * lHeight); if(nMode == 0) { //使用水平方向的结构元素进行膨胀 for(j = 0; j <lHeight; j++) { for(i = 1;i <lWidth-1; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成白色 *lpDst = (unsigned char)255; //源图像中当前点自身或者左右只要有一个点是黑色, //则将目标图像中的当前点赋成黑色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+n-1); if (pixel == 0 ) { *lpDst = (unsigned char)0; break; } } } } } else if(nMode == 1) { //使用垂直方向的结构元素进行膨胀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用1×3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成白色 *lpDst = (unsigned char)255; //源图像中当前点自身或者上下只要有一个点是黑色, //则将目标图像中的当前点赋成黑色 for (n = 0;n < 3;n++ ) { pixel = *(lpSrc+(n-1)*lWidth); if (pixel == 0 ) { *lpDst = (unsigned char)0; break; } } } } } else { //使用自定义的结构元素进行膨胀 for(j = 1; j <lHeight-1; j++) { for(i = 0;i <lWidth; i++) { //由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素 //和最上边和最下边的两列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //目标图像中的当前点先赋成白色 *lpDst = (unsigned char)255; //原图像中对应结构元素中为黑色的那些点中只要有一个是黑色, //则将目标图像中的当前点赋成黑色 //注意在DIB图像中内容是上下倒置的 for (m = 0;m < 3;m++ ) { for (n = 0;n < 3;n++) { if( structure[m][n] == -1) continue; pixel = *(lpSrc + ((2-m)-1)*lWidth + (n-1)); if (pixel == 0 ) { *lpDst = (unsigned char)0; break; } } } } } } // 复制膨胀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); return TRUE; } /************************************************************************* * * 函数名称: * CloseDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * int nMode - 闭运算方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素。 * int structure[3][3] - 自定义的3×3结构元素。 * * 返回值: * BOOL - 闭运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行开运算。结构元素为水平方向或垂直方向的三个点,中间点位于原点; * 或者由用户自己定义3×3的结构元素。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI CloseDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int nMode , int structure[3][3]) { if (DilationDIB(lpDIBBits, lWidth, lHeight, nMode , structure)) { if (ErosionDIB(lpDIBBits, lWidth, lHeight, nMode , structure)) { // 返回 return TRUE; } } return FALSE; // 返回 return TRUE; } /************************************************************************* * * 函数名称: * ThinDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 闭运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行细化运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI ThiningDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //脏标记 BOOL bModified; //循环变量 long i; long j; int n; int m; //四个条件 BOOL bCondition1; BOOL bCondition2; BOOL bCondition3; BOOL bCondition4; //计数器 unsigned char nCount; //像素值 unsigned char pixel; //5×5相邻区域像素值 unsigned char neighbour[5][5]; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); bModified=TRUE; while(bModified) { bModified = FALSE; // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); for(j = 2; j <lHeight-2; j++) { for(i = 2;i <lWidth-2; i++) { bCondition1 = FALSE; bCondition2 = FALSE; bCondition3 = FALSE; bCondition4 = FALSE; //由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素 // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) //return FALSE; continue; //如果源图像中当前点为白色,则跳过 else if(pixel == 255) continue; //获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表 for (m = 0;m < 5;m++ ) { for (n = 0;n < 5;n++) { neighbour[m][n] =(255 - (unsigned char)*(lpSrc + ((4 - m) - 2)*lWidth + n - 2 )) / 255; } } // neighbour[][] //逐个判断条件。 //判断2<=NZ(P1)<=6 nCount = neighbour[1][1] + neighbour[1][2] + neighbour[1][3] \ + neighbour[2][1] + neighbour[2][3] + \ + neighbour[3][1] + neighbour[3][2] + neighbour[3][3]; if ( nCount >= 2 && nCount <=6) bCondition1 = TRUE; //判断Z0(P1)=1 nCount = 0; if (neighbour[1][2] == 0 && neighbour[1][1] == 1) nCount++; if (neighbour[1][1] == 0 && neighbour[2][1] == 1) nCount++; if (neighbour[2][1] == 0 && neighbour[3][1] == 1) nCount++; if (neighbour[3][1] == 0 && neighbour[3][2] == 1) nCount++; if (neighbour[3][2] == 0 && neighbour[3][3] == 1) nCount++; if (neighbour[3][3] == 0 && neighbour[2][3] == 1) nCount++; if (neighbour[2][3] == 0 && neighbour[1][3] == 1) nCount++; if (neighbour[1][3] == 0 && neighbour[1][2] == 1) nCount++; if (nCount == 1) bCondition2 = TRUE; //判断P2*P4*P8=0 or Z0(p2)!=1 if (neighbour[1][2]*neighbour[2][1]*neighbour[2][3] == 0) bCondition3 = TRUE; else { nCount = 0; if (neighbour[0][2] == 0 && neighbour[0][1] == 1) nCount++; if (neighbour[0][1] == 0 && neighbour[1][1] == 1) nCount++; if (neighbour[1][1] == 0 && neighbour[2][1] == 1) nCount++; if (neighbour[2][1] == 0 && neighbour[2][2] == 1) nCount++; if (neighbour[2][2] == 0 && neighbour[2][3] == 1) nCount++; if (neighbour[2][3] == 0 && neighbour[1][3] == 1) nCount++; if (neighbour[1][3] == 0 && neighbour[0][3] == 1) nCount++; if (neighbour[0][3] == 0 && neighbour[0][2] == 1) nCount++; if (nCount != 1) bCondition3 = TRUE; } //判断P2*P4*P6=0 or Z0(p4)!=1 if (neighbour[1][2]*neighbour[2][1]*neighbour[3][2] == 0) bCondition4 = TRUE; else { nCount = 0; if (neighbour[1][1] == 0 && neighbour[1][0] == 1) nCount++; if (neighbour[1][0] == 0 && neighbour[2][0] == 1) nCount++; if (neighbour[2][0] == 0 && neighbour[3][0] == 1) nCount++; if (neighbour[3][0] == 0 && neighbour[3][1] == 1) nCount++; if (neighbour[3][1] == 0 && neighbour[3][2] == 1) nCount++; if (neighbour[3][2] == 0 && neighbour[2][2] == 1) nCount++; if (neighbour[2][2] == 0 && neighbour[1][2] == 1) nCount++; if (neighbour[1][2] == 0 && neighbour[1][1] == 1) nCount++; if (nCount != 1) bCondition4 = TRUE; } if(bCondition1 && bCondition2 && bCondition3 && bCondition4) { *lpDst = (unsigned char)255; bModified = TRUE; } else { *lpDst = (unsigned char)0; } } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * RobertDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 边缘检测成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用Robert边缘检测算子对图像进行边缘检测运算。 * * 要求目标图像为灰度图像。 ************************************************************************/ BOOL WINAPI RobertDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; //像素值 double result; unsigned char pixel[4]; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); //使用水平方向的结构元素进行腐蚀 for(j = lHeight-1; j > 0; j--) { for(i = 0;i <lWidth-1; i++) { //由于使用2×2的模板,为防止越界,所以不处理最下边和最右边的两列像素 // 指向源图像第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处2*2区域的像素值,注意要转换为unsigned char型 pixel[0] = (unsigned char)*lpSrc; pixel[1] = (unsigned char)*(lpSrc + 1); pixel[2] = (unsigned char)*(lpSrc - lWidth); pixel[3] = (unsigned char)*(lpSrc - lWidth + 1); //计算目标图像中的当前点 result = sqrt(( pixel[0] - pixel[3] )*( pixel[0] - pixel[3] ) + \ ( pixel[1] - pixel[2] )*( pixel[1] - pixel[2] )); *lpDst = (unsigned char)result; } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * SobelDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 边缘检测成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用Sobel边缘检测算子对图像进行边缘检测运算。 * * 要求目标图像为灰度图像。 ************************************************************************/ BOOL WINAPI SobelDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向缓存图像的指针 LPSTR lpDst1; LPSTR lpDst2; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits1; HLOCAL hNewDIBBits1; LPSTR lpNewDIBBits2; HLOCAL hNewDIBBits2; //循环变量 long i; long j; // 模板高度 int iTempH; // 模板宽度 int iTempW; // 模板系数 FLOAT fTempC; // 模板中心元素X坐标 int iTempMX; // 模板中心元素Y坐标 int iTempMY; //模板数组 FLOAT aTemplate[9]; // 暂时分配内存,以保存新图像 hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits1 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); // 暂时分配内存,以保存新图像 hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits2 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst1 = (char *)lpNewDIBBits1; memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight); lpDst2 = (char *)lpNewDIBBits2; memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Sobel模板参数 iTempW = 3; iTempH = 3; fTempC = 1.0; iTempMX = 1; iTempMY = 1; aTemplate[0] = -1.0; aTemplate[1] = -2.0; aTemplate[2] = -1.0; aTemplate[3] = 0.0; aTemplate[4] = 0.0; aTemplate[5] = 0.0; aTemplate[6] = 1.0; aTemplate[7] = 2.0; aTemplate[8] = 1.0; // 调用Template()函数 if (!Template(lpNewDIBBits1, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 设置Sobel模板参数 aTemplate[0] = -1.0; aTemplate[1] = 0.0; aTemplate[2] = 1.0; aTemplate[3] = -2.0; aTemplate[4] = 0.0; aTemplate[5] = 2.0; aTemplate[6] = -1.0; aTemplate[7] = 0.0; aTemplate[8] = 1.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits1); LocalFree(hNewDIBBits1); LocalUnlock(hNewDIBBits2); LocalFree(hNewDIBBits2); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * PrewittDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 边缘检测成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用Prewitt边缘检测算子对图像进行边缘检测运算。 * * 要求目标图像为灰度图像。 ************************************************************************/ BOOL WINAPI PrewittDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向缓存图像的指针 LPSTR lpDst1; LPSTR lpDst2; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits1; HLOCAL hNewDIBBits1; LPSTR lpNewDIBBits2; HLOCAL hNewDIBBits2; //循环变量 long i; long j; // 模板高度 int iTempH; // 模板宽度 int iTempW; // 模板系数 FLOAT fTempC; // 模板中心元素X坐标 int iTempMX; // 模板中心元素Y坐标 int iTempMY; //模板数组 FLOAT aTemplate[9]; // 暂时分配内存,以保存新图像 hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits1 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); // 暂时分配内存,以保存新图像 hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits2 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst1 = (char *)lpNewDIBBits1; memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight); lpDst2 = (char *)lpNewDIBBits2; memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Prewitt模板参数 iTempW = 3; iTempH = 3; fTempC = 1.0; iTempMX = 1; iTempMY = 1; aTemplate[0] = -1.0; aTemplate[1] = -1.0; aTemplate[2] = -1.0; aTemplate[3] = 0.0; aTemplate[4] = 0.0; aTemplate[5] = 0.0; aTemplate[6] = 1.0; aTemplate[7] = 1.0; aTemplate[8] = 1.0; // 调用Template()函数 if (!Template(lpNewDIBBits1, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 设置Prewitt模板参数 aTemplate[0] = 1.0; aTemplate[1] = 0.0; aTemplate[2] = -1.0; aTemplate[3] = 1.0; aTemplate[4] = 0.0; aTemplate[5] = -1.0; aTemplate[6] = 1.0; aTemplate[7] = 0.0; aTemplate[8] = -1.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits1); LocalFree(hNewDIBBits1); LocalUnlock(hNewDIBBits2); LocalFree(hNewDIBBits2); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * KirschDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 边缘检测成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用kirsch边缘检测算子对图像进行边缘检测运算。 * * 要求目标图像为灰度图像。 ************************************************************************/ BOOL WINAPI KirschDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向缓存图像的指针 LPSTR lpDst1; LPSTR lpDst2; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits1; HLOCAL hNewDIBBits1; LPSTR lpNewDIBBits2; HLOCAL hNewDIBBits2; //循环变量 long i; long j; // 模板高度 int iTempH; // 模板宽度 int iTempW; // 模板系数 FLOAT fTempC; // 模板中心元素X坐标 int iTempMX; // 模板中心元素Y坐标 int iTempMY; //模板数组 FLOAT aTemplate[9]; // 暂时分配内存,以保存新图像 hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits1 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); // 暂时分配内存,以保存新图像 hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits2 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst1 = (char *)lpNewDIBBits1; memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight); lpDst2 = (char *)lpNewDIBBits2; memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板1参数 iTempW = 3; iTempH = 3; fTempC = 1.0; iTempMX = 1; iTempMY = 1; aTemplate[0] = 5.0; aTemplate[1] = 5.0; aTemplate[2] = 5.0; aTemplate[3] = -3.0; aTemplate[4] = 0.0; aTemplate[5] = -3.0; aTemplate[6] = -3.0; aTemplate[7] = -3.0; aTemplate[8] = -3.0; // 调用Template()函数 if (!Template(lpNewDIBBits1, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 设置Kirsch模板2参数 aTemplate[0] = -3.0; aTemplate[1] = 5.0; aTemplate[2] = 5.0; aTemplate[3] = -3.0; aTemplate[4] = 0.0; aTemplate[5] = 5.0; aTemplate[6] = -3.0; aTemplate[7] = -3.0; aTemplate[8] = -3.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板3参数 aTemplate[0] = -3.0; aTemplate[1] = -3.0; aTemplate[2] = 5.0; aTemplate[3] = -3.0; aTemplate[4] = 0.0; aTemplate[5] = 5.0; aTemplate[6] = -3.0; aTemplate[7] = -3.0; aTemplate[8] = 5.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板4参数 aTemplate[0] = -3.0; aTemplate[1] = -3.0; aTemplate[2] = -3.0; aTemplate[3] = -3.0; aTemplate[4] = 0.0; aTemplate[5] = 5.0; aTemplate[6] = -3.0; aTemplate[7] = 5.0; aTemplate[8] = 5.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板5参数 aTemplate[0] = -3.0; aTemplate[1] = -3.0; aTemplate[2] = -3.0; aTemplate[3] = -3.0; aTemplate[4] = 0.0; aTemplate[5] = -3.0; aTemplate[6] = 5.0; aTemplate[7] = 5.0; aTemplate[8] = 5.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板6参数 aTemplate[0] = -3.0; aTemplate[1] = -3.0; aTemplate[2] = -3.0; aTemplate[3] = 5.0; aTemplate[4] = 0.0; aTemplate[5] = -3.0; aTemplate[6] = 5.0; aTemplate[7] = 5.0; aTemplate[8] = -3.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板7参数 aTemplate[0] = 5.0; aTemplate[1] = -3.0; aTemplate[2] = -3.0; aTemplate[3] = 5.0; aTemplate[4] = 0.0; aTemplate[5] = -3.0; aTemplate[6] = 5.0; aTemplate[7] = -3.0; aTemplate[8] = -3.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 拷贝源图像到缓存图像中 memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Kirsch模板8参数 aTemplate[0] = 5.0; aTemplate[1] = 5.0; aTemplate[2] = -3.0; aTemplate[3] = 5.0; aTemplate[4] = 0.0; aTemplate[5] = -3.0; aTemplate[6] = -3.0; aTemplate[7] = -3.0; aTemplate[8] = -3.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits1); LocalFree(hNewDIBBits1); LocalUnlock(hNewDIBBits2); LocalFree(hNewDIBBits2); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * GaussDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 边缘检测成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用高斯拉普拉斯边缘检测算子对图像进行边缘检测运算。 * * 要求目标图像为灰度图像。 ************************************************************************/ BOOL WINAPI GaussDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向缓存图像的指针 LPSTR lpDst1; LPSTR lpDst2; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits1; HLOCAL hNewDIBBits1; LPSTR lpNewDIBBits2; HLOCAL hNewDIBBits2; // 模板高度 int iTempH; // 模板宽度 int iTempW; // 模板系数 FLOAT fTempC; // 模板中心元素X坐标 int iTempMX; // 模板中心元素Y坐标 int iTempMY; //模板数组 FLOAT aTemplate[25]; // 暂时分配内存,以保存新图像 hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits1 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); // 暂时分配内存,以保存新图像 hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits2 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst1 = (char *)lpNewDIBBits1; memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight); lpDst2 = (char *)lpNewDIBBits2; memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Gauss模板参数 iTempW = 5; iTempH = 5; fTempC = 1.0; iTempMX = 3; iTempMY = 3; aTemplate[0] = -2.0; aTemplate[1] = -4.0; aTemplate[2] = -4.0; aTemplate[3] = -4.0; aTemplate[4] = -2.0; aTemplate[5] = -4.0; aTemplate[6] = 0.0; aTemplate[7] = 8.0; aTemplate[8] = 0.0; aTemplate[9] = -4.0; aTemplate[10] = -4.0; aTemplate[11] = 8.0; aTemplate[12] = 24.0; aTemplate[13] = 8.0; aTemplate[14] = -4.0; aTemplate[15] = -4.0; aTemplate[16] = 0.0; aTemplate[17] = 8.0; aTemplate[18] = 0.0; aTemplate[19] = -4.0; aTemplate[20] = -2.0; aTemplate[21] = -4.0; aTemplate[22] = -4.0; aTemplate[23] = -4.0; aTemplate[24] = -2.0; // 调用Template()函数 if (!Template(lpNewDIBBits1, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits1); LocalFree(hNewDIBBits1); LocalUnlock(hNewDIBBits2); LocalFree(hNewDIBBits2); // 返回 return TRUE; } BOOL WINAPI DifferDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; // 模板高度 int iTempH; // 模板宽度 int iTempW; // 模板系数 FLOAT fTempC; // 模板中心元素X坐标 int iTempMX; // 模板中心元素Y坐标 int iTempMY; //模板数组 FLOAT aTemplate[3]; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 拷贝源图像到缓存图像中 lpDst = (char *)lpNewDIBBits; memcpy(lpNewDIBBits, lpDIBBits, lWidth * lHeight); // 设置Sobel模板参数 iTempW = 3; iTempH = 1; fTempC = 1.0; iTempMX = 1; iTempMY = 0; aTemplate[0] = 0.0; aTemplate[1] = 1.0; aTemplate[2] = -1.0; // 调用Template()函数 if (!Template(lpNewDIBBits, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * Template() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * int iTempH - 模板的高度 * int iTempW - 模板的宽度 * int iTempMX - 模板的中心元素X坐标 ( < iTempW - 1) * int iTempMY - 模板的中心元素Y坐标 ( < iTempH - 1) * FLOAT * fpArray - 指向模板数组的指针 * FLOAT fCoef - 模板系数 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用指定的模板(任意大小)来对图像进行操作,参数iTempH指定模板 * 的高度,参数iTempW指定模板的宽度,参数iTempMX和iTempMY指定模板的中心 * 元素坐标,参数fpArray指定模板元素,fCoef指定系数。 * ************************************************************************/ BOOL WINAPI Template(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int iTempH, int iTempW, int iTempMX, int iTempMY, FLOAT * fpArray, FLOAT fCoef) { // 指向复制图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 指向源图像的指针 unsigned char* lpSrc; // 指向要复制区域的指针 unsigned char* lpDst; // 循环变量 LONG i; LONG j; LONG k; LONG l; // 计算结果 FLOAT fResult; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight); // 判断是否内存分配失败 if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化图像为原始图像 memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight); // 行(除去边缘几行) for(i = iTempMY; i < lHeight - iTempH + iTempMY + 1; i++) { // 列(除去边缘几列) for(j = iTempMX; j < lWidth - iTempW + iTempMX + 1; j++) { // 指向新DIB第i行,第j个象素的指针 lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j; fResult = 0; // 计算 for (k = 0; k < iTempH; k++) { for (l = 0; l < iTempW; l++) { // 指向DIB第i - iTempMY + k行,第j - iTempMX + l个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i + iTempMY - k) + j - iTempMX + l; // 保存象素值 fResult += (* lpSrc) * fpArray[k * iTempW + l]; } } // 乘上系数 fResult *= fCoef; // 取绝对值 fResult = (FLOAT ) fabs(fResult); // 判断是否超过255 if(fResult > 255) { // 直接赋值为255 * lpDst = 255; } else { // 赋值 * lpDst = (unsigned char) (fResult + 0.5); } } } // 复制变换后的图像 memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * MedianFilter() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * int iFilterH - 滤波器的高度 * int iFilterW - 滤波器的宽度 * int iFilterMX - 滤波器的中心元素X坐标 * int iFilterMY - 滤波器的中心元素Y坐标 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数对DIB图像进行中值滤波。 * ************************************************************************/ BOOL WINAPI MedianFilter(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int iFilterH, int iFilterW, int iFilterMX, int iFilterMY) { // 指向源图像的指针 unsigned char* lpSrc; // 指向要复制区域的指针 unsigned char* lpDst; // 指向复制图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 指向滤波器数组的指针 unsigned char * aValue; HLOCAL hArray; // 循环变量 LONG i; LONG j; LONG k; LONG l; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight); // 判断是否内存分配失败 if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化图像为原始图像 memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight); // 暂时分配内存,以保存滤波器数组 hArray = LocalAlloc(LHND, iFilterH * iFilterW); // 判断是否内存分配失败 if (hArray == NULL) { // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 分配内存失败 return FALSE; } // 锁定内存 aValue = (unsigned char * )LocalLock(hArray); // 开始中值滤波 // 行(除去边缘几行) for(i = iFilterMY; i < lHeight - iFilterH + iFilterMY + 1; i++) { // 列(除去边缘几列) for(j = iFilterMX; j < lWidth - iFilterW + iFilterMX + 1; j++) { // 指向新DIB第i行,第j个象素的指针 lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 读取滤波器数组 for (k = 0; k < iFilterH; k++) { for (l = 0; l < iFilterW; l++) { // 指向DIB第i - iFilterMY + k行,第j - iFilterMX + l个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i + iFilterMY - k) + j - iFilterMX + l; // 保存象素值 aValue[k * iFilterW + l] = *lpSrc; } } // 获取中值 * lpDst = GetMedianNum(aValue, iFilterH * iFilterW); } } // 复制变换后的图像 memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); LocalUnlock(hArray); LocalFree(hArray); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * GetMedianNum() * * 参数: * unsigned char * bpArray - 指向要获取中值的数组指针 * int iFilterLen - 数组长度 * * 返回值: * unsigned char - 返回指定数组的中值。 * * 说明: * 该函数用冒泡法对一维数组进行排序,并返回数组元素的中值。 * ************************************************************************/ unsigned char WINAPI GetMedianNum(unsigned char * bArray, int iFilterLen) { // 循环变量 int i; int j; // 中间变量 unsigned char bTemp; // 用冒泡法对数组进行排序 for (j = 0; j < iFilterLen - 1; j ++) { for (i = 0; i < iFilterLen - j - 1; i ++) { if (bArray[i] > bArray[i + 1]) { // 互换 bTemp = bArray[i]; bArray[i] = bArray[i + 1]; bArray[i + 1] = bTemp; } } } // 计算中值 if ((iFilterLen & 1) > 0) { // 数组有奇数个元素,返回中间一个元素 bTemp = bArray[(iFilterLen + 1) / 2]; } else { // 数组有偶数个元素,返回中间两个元素平均值 bTemp = (bArray[iFilterLen / 2] + bArray[iFilterLen / 2 + 1]) / 2; } // 返回中值 return bTemp; } /************************************************************************* * * 函数名称: * GradSharp() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * BYTE bThre - 阈值 * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行梯度锐化。 * ************************************************************************/ BOOL WINAPI GradSharp(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bThre) { // 指向源图像的指针 unsigned char* lpSrc; unsigned char* lpSrc1; unsigned char* lpSrc2; // 循环变量 LONG i; LONG j; // 图像每行的字节数 LONG lLineBytes; // 中间变量 BYTE bTemp; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 每行 for(i = 0; i < lHeight; i++) { // 每列 for(j = 0; j < lWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 指向DIB第i+1行,第j个象素的指针 lpSrc1 = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 2 - i) + j; // 指向DIB第i行,第j+1个象素的指针 lpSrc2 = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j + 1; bTemp = abs((*lpSrc)-(*lpSrc1)) + abs((*lpSrc)-(*lpSrc2)); // 判断是否小于阈值 if (bTemp < 255) { // 判断是否大于阈值,对于小于情况,灰度值不变。 if (bTemp >= bThre) { // 直接赋值为bTemp *lpSrc = bTemp; } } else { // 直接赋值为255 *lpSrc = 255; } } } // 返回 return TRUE; } /************************************************************************* * * 函数名称: * RowScanDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行水平投影运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ int* RowscanDIB2(LPSTR lpDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine) { // AfxMessageBox("Start..."); // 指向源图像的指针 LPSTR lpSrc,lpSrcformer,lpSrclater; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 分割后图像的宽度和高度 LONG lNewWidth = 140; LONG lNewHeight = 40; //循环变量 long i; long j; long k; // 获取车牌位置信息 int *pPlatePosi; int iPlateLine[40]; for(i=0;i<40;i++) { iPlateLine[i]=*pPlateLine; pPlateLine++; } // 图像中每行象素由 0->255 或 255->0 的次数 long lGrayChangeNumber; // 前一个像素值 unsigned char pixelformer; // 后一个像素值 unsigned char pixellater; // 满足条件底行的位置 int iLineLocation; // 连续出现变化次数超过阈值的行数 int iLineNumber; // 满足条件的区域的上界 int iTopLine; // 满足条件的区域的下界 int iLowLine; // 满足条件的区域的左边界 int iLeftLine; // 满足条件的区域的右边界 int iRightLine; // 图像每行的字节数 LONG lLineBytes; // 新图像每行的字节数 LONG lNewLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lNewLineBytes = WIDTHBYTES( lNewWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变 // 标明是否找到车牌(第一个数),及车牌位置(后四个数) int iPlatePosition[5] = {0,0,0,0,0}; if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lNewLineBytes * lNewHeight); iLineLocation = 0; iLineNumber = 0; iTopLine = 0; iLowLine = 0; // 记录满足条件的行的位置 int iLineNum[100]; for(i=0;i<100;i++) { iLineNum[i]=0; } int iLineNum1; iLineNum1 = 0; //int a1,a2,b1,b2; // 初步寻找满足条件的行,条件1:在一行内存在一连续的长度约为140的条形区域变化率大于10 for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++) { for (i = 0; i < lWidth - 140; i++) { lGrayChangeNumber = 0; // 对每一行用宽度为160的窗进行处理 for(k=0;k<140;k++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i + k; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i + k + 1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } if (lGrayChangeNumber >= 10) { iLineNum[iLineNum1]=j; iLineNum1++; break; } } } if(iLineNum1<10) { AfxMessageBox("非车牌区域"); pPlatePosi = &iPlatePosition[0]; return pPlatePosi; } // 进一步确定行的位置,条件2:满足条件1的各行是否有10行是近似相邻的 for(i=0;i<iLineNum1-1-10;i++) { for(j=0;j<10;j++) { if(abs(iLineNum[j+i+10]-iLineNum[j+i])<13) { iTopLine=iLineNum[j+i+10]+5;// 微调车牌上下界 iLowLine = iTopLine -40; } } } // if (lGrayChangeNumber >= 10) // { // 判断前后满足条件的行是否是相邻 // if((iLineLocation == j-1) || (iLineLocation == j-2)) // { // iLineNumber++; // } // 记录满足条件的行的新位置 // iLineLocation = j; // } // 确定满足条件的区域的上下边界 // if((iLineNumber >=20) && (iLineNumber <=100)) // { // iTopLine = iLineLocation+10; // iLowLine = iLineLocation - 30; // break; // } // } iLineLocation = 0; iLineNumber = 0; iLeftLine = 0; iRightLine = 0; iLineNum1 = 0; // 初步寻找满足条件的列,条件1:在一列内白色象素的数目大于5 for (i = 0;i < lWidth ;i++) { lGrayChangeNumber = 0; for(j = iLowLine;j < iTopLine ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; // lpSrclater = (char *)lpDIBBits + lLineBytes * (j+1) + i ; pixelformer = (unsigned char)*lpSrcformer; // pixellater = (unsigned char)*lpSrclater; if (pixelformer == (BYTE)255) { lGrayChangeNumber++; // TRACE("%d\t",lGrayChangeNumber); } } if (lGrayChangeNumber >= 5) { iLineNum[iLineNum1]=i; iLineNum1++; } } if(iLineNum1<60) { AfxMessageBox("非车牌区域"); pPlatePosi = &iPlatePosition[0]; return pPlatePosi; } // 进一步确定列的位置,条件2:满足条件1的各列是否有80行是近似相邻的 for(i=0;i<iLineNum1-1-40;i++) { int a1=0; for(j=0;j<40;j++) { if(abs(iLineNum[j+i+40]-iLineNum[j+i])<100) { iLeftLine=iLineNum[j+i] - 5;// 微调车牌左右界 iRightLine = iLeftLine + 140; int q1=0; break; } } if(iLeftLine>0) break; } int q=0; for (j = iLowLine; j < iTopLine; j++) { for (i = iLeftLine; i < iRightLine; i++) { lpSrc = (char *)lpDIBBits + lLineBytes * j + i; lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine); *lpDst = *lpSrc; } } /* for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++) { lGrayChangeNumber = 0; for (i = 0; i < lWidth - 1; i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i +1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } // 记录满足条件的行的位置 if (lGrayChangeNumber >= 10) { // 判断前后满足条件的行是否是相邻 if((iLineLocation == j-1) || (iLineLocation == j-2)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = j; } // 确定满足条件的区域的上下边界 if((iLineNumber >=20) && (iLineNumber <=100)) { iTopLine = iLineLocation+10; iLowLine = iLineLocation - 30; break; } } iLineLocation = 0; iLineNumber = 0; iLeftLine = 0; iRightLine = 0; for (i = 0;i < lWidth ;i++) { lGrayChangeNumber = 0; for(j = iLowLine;j < iTopLine ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * (j+1) + i ; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; // TRACE("%d\t",lGrayChangeNumber); } } if (lGrayChangeNumber >= 2) { // 判断前后满足条件的是否是相邻 if((iLineLocation == i-1) && (iLineLocation >= i-20)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = i; // TRACE("%d\t",lGrayChangeNumber); } // 确定满足条件的区域的左右边界 if((iLineNumber >=80) && (iLineNumber <=150)) { iLeftLine = iLineLocation -90; iRightLine = iLeftLine + 140; // TRACE("%d\t",i); break; } } int q=0; for (j = iLowLine; j < iTopLine; j++) { for (i = iLeftLine; i < iRightLine; i++) { lpSrc = (char *)lpDIBBits + lLineBytes * j + i; lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine); *lpDst = *lpSrc; } } */ // for (j = 0; j < 40; j++) // { // for(i = 0; i < 140; i++) // { // // lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i; // lpDst = (char *)lpDIBBits + lLineBytes * j + i; // *lpDst = *lpSrc; // } // } // 传递车牌位置 iPlatePosition[0] = 1; iPlatePosition[1] = iTopLine; iPlatePosition[2] = iLowLine; iPlatePosition[3] = iLeftLine; iPlatePosition[4] = iRightLine; pPlatePosi = &iPlatePosition[0]; // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return pPlatePosi; } /************************************************************************* * * 函数名称: * RowScanDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行水平投影运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ int* RowscanDIB3(LPSTR lpDIBBits, LPSTR lpOrgDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine) { // AfxMessageBox("Start..."); // 指向源图像的指针 LPSTR lpSrc,lpSrcformer,lpSrclater; // 指向原始图像(汽车整车图像) LPSTR lpSrcOrg; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 分割后图像的宽度和高度 LONG lNewWidth = 140; LONG lNewHeight = 40; //循环变量 long i; long j; long k; // 获取车牌位置信息 int *pPlatePosi; int iPlateLine[40]; for(i=0;i<40;i++) { iPlateLine[i]=*pPlateLine; pPlateLine++; } // 图像中每行象素由 0->255 或 255->0 的次数 long lGrayChangeNumber; // 前一个像素值 unsigned char pixelformer; // 后一个像素值 unsigned char pixellater; // 满足条件底行的位置 int iLineLocation; // 连续出现变化次数超过阈值的行数 int iLineNumber; // 满足条件的区域的上界 int iTopLine; // 满足条件的区域的下界 int iLowLine; // 满足条件的区域的左边界 int iLeftLine; // 满足条件的区域的右边界 int iRightLine; // 图像每行的字节数 LONG lLineBytes; // 新图像每行的字节数 LONG lNewLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lNewLineBytes = WIDTHBYTES( lNewWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变 // 标明是否找到车牌(第一个数),及车牌位置(后四个数) int iPlatePosition[5] = {0,0,0,0,0}; if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lNewLineBytes * lNewHeight); iLineLocation = 0; iLineNumber = 0; iTopLine = 0; iLowLine = 0; // 记录满足条件的行的位置 int iLineNum[100]; for(i=0;i<100;i++) { iLineNum[i]=0; } int iLineNum1; iLineNum1 = 0; //int a1,a2,b1,b2; // 初步寻找满足条件的行,条件1:在一行内存在一连续的长度约为140的条形区域变化率大于10 for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++) { for (i = 0; i < lWidth - 140; i++) { lGrayChangeNumber = 0; // 对每一行用宽度为160的窗进行处理 for(k=0;k<140;k++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i + k; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i + k + 1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } if (lGrayChangeNumber >= 10) { iLineNum[iLineNum1]=j; iLineNum1++; break; } } } if(iLineNum1<10) { AfxMessageBox("非车牌区域"); pPlatePosi = &iPlatePosition[0]; return pPlatePosi; } // 进一步确定行的位置,条件2:满足条件1的各行是否有10行是近似相邻的 for(i=0;i<iLineNum1-1-10;i++) { for(j=0;j<10;j++) { if(abs(iLineNum[j+i+10]-iLineNum[j+i])<13) { iTopLine=iLineNum[j+i+10]+5;// 微调车牌上下界 iLowLine = iTopLine -40; } } } // if (lGrayChangeNumber >= 10) // { // 判断前后满足条件的行是否是相邻 // if((iLineLocation == j-1) || (iLineLocation == j-2)) // { // iLineNumber++; // } // 记录满足条件的行的新位置 // iLineLocation = j; // } // 确定满足条件的区域的上下边界 // if((iLineNumber >=20) && (iLineNumber <=100)) // { // iTopLine = iLineLocation+10; // iLowLine = iLineLocation - 30; // break; // } // } iLineLocation = 0; iLineNumber = 0; iLeftLine = 0; iRightLine = 0; iLineNum1 = 0; // 初步寻找满足条件的列,条件1:在一列内白色象素的数目大于5 for (i = 0;i < lWidth ;i++) { lGrayChangeNumber = 0; for(j = iLowLine;j < iTopLine ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; // lpSrclater = (char *)lpDIBBits + lLineBytes * (j+1) + i ; pixelformer = (unsigned char)*lpSrcformer; // pixellater = (unsigned char)*lpSrclater; if (pixelformer == (BYTE)255) { lGrayChangeNumber++; // TRACE("%d\t",lGrayChangeNumber); } } if (lGrayChangeNumber >= 5) { iLineNum[iLineNum1]=i; iLineNum1++; } } if(iLineNum1<60) { AfxMessageBox("非车牌区域"); pPlatePosi = &iPlatePosition[0]; return pPlatePosi; } // 进一步确定列的位置,条件2:满足条件1的各列是否有80行是近似相邻的 for(i=0;i<iLineNum1-1-40;i++) { int a1=0; for(j=0;j<40;j++) { if(abs(iLineNum[j+i+40]-iLineNum[j+i])<100) { iLeftLine=iLineNum[j+i] - 5;// 微调车牌左右界 iRightLine = iLeftLine + 140; int q1=0; break; } } if(iLeftLine>0) break; } int q=0; for (j = iLowLine; j < iTopLine; j++) { for (i = iLeftLine; i < iRightLine; i++) { lpSrc = (char *)lpOrgDIBBits + lLineBytes * j + i; lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine); *lpDst = *lpSrc; } } /* for (j = abs(iPlateLine[0]); j <abs(iPlateLine[1]); j++) { lGrayChangeNumber = 0; for (i = 0; i < lWidth - 1; i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i +1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } // 记录满足条件的行的位置 if (lGrayChangeNumber >= 10) { // 判断前后满足条件的行是否是相邻 if((iLineLocation == j-1) || (iLineLocation == j-2)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = j; } // 确定满足条件的区域的上下边界 if((iLineNumber >=20) && (iLineNumber <=100)) { iTopLine = iLineLocation+10; iLowLine = iLineLocation - 30; break; } } iLineLocation = 0; iLineNumber = 0; iLeftLine = 0; iRightLine = 0; for (i = 0;i < lWidth ;i++) { lGrayChangeNumber = 0; for(j = iLowLine;j < iTopLine ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * (j+1) + i ; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; // TRACE("%d\t",lGrayChangeNumber); } } if (lGrayChangeNumber >= 2) { // 判断前后满足条件的是否是相邻 if((iLineLocation == i-1) && (iLineLocation >= i-20)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = i; // TRACE("%d\t",lGrayChangeNumber); } // 确定满足条件的区域的左右边界 if((iLineNumber >=80) && (iLineNumber <=150)) { iLeftLine = iLineLocation -90; iRightLine = iLeftLine + 140; // TRACE("%d\t",i); break; } } int q=0; for (j = iLowLine; j < iTopLine; j++) { for (i = iLeftLine; i < iRightLine; i++) { lpSrc = (char *)lpDIBBits + lLineBytes * j + i; lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine); *lpDst = *lpSrc; } } */ // for (j = 0; j < 40; j++) // { // for(i = 0; i < 140; i++) // { // // lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i; // lpDst = (char *)lpDIBBits + lLineBytes * j + i; // *lpDst = *lpSrc; // } // } // 传递车牌位置 iPlatePosition[0] = 1; iPlatePosition[1] = iTopLine; iPlatePosition[2] = iLowLine; iPlatePosition[3] = iLeftLine; iPlatePosition[4] = iRightLine; pPlatePosi = &iPlatePosition[0]; // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return pPlatePosi; } /************************************************************************* * * 函数名称: * RowScanDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行水平投影运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ // 用于车牌区域归一化的处理 int* RowscanDIB4(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // AfxMessageBox("Start..."); // 指向源图像的指针 LPSTR lpSrc,lpSrcformer,lpSrclater; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 获取车牌位置信息 int *pPlatePosi; // 分割后图像的宽度和高度 LONG lNewWidth = 140; LONG lNewHeight = 40; //循环变量 long i; long j; // 图像中每行象素由 0->255 或 255->0 的次数 long lGrayChangeNumber; // 前一个像素值 unsigned char pixelformer; // 后一个像素值 unsigned char pixellater; // 满足条件底行的位置 int iLineLocation; // 连续出现变化次数超过阈值的行数 int iLineNumber; // 满足条件的区域的上界 int iTopLine; // 满足条件的区域的下界 int iLowLine; // 满足条件的区域的左边界 int iLeftLine; // 满足条件的区域的右边界 int iRightLine; // 图像每行的字节数 LONG lLineBytes; // 新图像每行的字节数 LONG lNewLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lNewLineBytes = WIDTHBYTES( lNewWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变 if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)0, lNewLineBytes * lNewHeight); iLineLocation = 0; iLineNumber = 0; iTopLine = 0; iLowLine = 0; for (j = 0; j < lHeight; j++) { lGrayChangeNumber = 0; for (i = 0; i < lWidth - 1; i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i +1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } // 记录满足条件的行的位置 if (lGrayChangeNumber >= 10) { // 判断前后满足条件的行是否是相邻 if(iLineLocation == j-1)//|| (iLineLocation == j-2)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = j; } // 确定满足条件的区域的上下边界 if((lGrayChangeNumber == 0) && (iLineNumber > 15)) break; } // iLineLocation和 iLineLocation-iLineNumber是准确上下界 iLowLine = iLineLocation - iLineNumber - 3; iTopLine = iLowLine + iLineNumber + 6; iLeftLine = 0; iRightLine = 140; /* for (i = 0;i < lWidth ;i++) { lGrayChangeNumber = 0; for(j = iLowLine;j < iTopLine ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * (j+1) + i ; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; // TRACE("%d\t",lGrayChangeNumber); } } if (lGrayChangeNumber >= 2) { // 判断前后满足条件的是否是相邻 if((iLineLocation == i-1) && (iLineLocation >= i-20)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = i; // TRACE("%d\t",lGrayChangeNumber); } // 确定满足条件的区域的左右边界 if((iLineNumber >=80) && (iLineNumber <=150)) { iLeftLine = iLineLocation -90; iRightLine = iLeftLine + 140; // TRACE("%d\t",i); break; } } */ int q=0; for (j = iLowLine; j < iTopLine; j++) { for (i = iLeftLine; i < iRightLine; i++) { lpSrc = (char *)lpDIBBits + lLineBytes * j + i; lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine); *lpDst = *lpSrc; } } // for (j = 0; j < 40; j++) // { // for(i = 0; i < 140; i++) // { // // lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i; // lpDst = (char *)lpDIBBits + lLineBytes * j + i; // *lpDst = *lpSrc; // } // } // 传递车牌位置 int iPlatePosition[2] = {0,0}; iPlatePosition[0] = iTopLine; iPlatePosition[1] = iLowLine; // iPlatePosition[2] = iLeftLine; // iPlatePosition[3] = iRightLine; pPlatePosi = &iPlatePosition[0]; // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 // return TRUE; return pPlatePosi; } /************************************************************************* * * 函数名称: * RowScanDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行水平投影运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ int* RowscanDIB1(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // AfxMessageBox("Start..."); // 指向源图像的指针 LPSTR lpSrc,lpSrcformer,lpSrclater; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 获取车牌位置信息 int *pPlatePosi; // 分割后图像的宽度和高度 LONG lNewWidth = 140; LONG lNewHeight = 40; //循环变量 long i; long j; // 图像中每行象素由 0->255 或 255->0 的次数 long lGrayChangeNumber; // 前一个像素值 unsigned char pixelformer; // 后一个像素值 unsigned char pixellater; // 满足条件底行的位置 int iLineLocation; // 连续出现变化次数超过阈值的行数 int iLineNumber; // 满足条件的区域的上界 int iTopLine; // 满足条件的区域的下界 int iLowLine; // 满足条件的区域的左边界 int iLeftLine; // 满足条件的区域的右边界 int iRightLine; // 图像每行的字节数 LONG lLineBytes; // 新图像每行的字节数 LONG lNewLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lNewLineBytes = WIDTHBYTES( lNewWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lNewHeight); // 在此分配的内存的大小将来要改变 if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lNewLineBytes * lNewHeight); iLineLocation = 0; iLineNumber = 0; iTopLine = 0; iLowLine = 0; for (j = 0; j < lHeight; j++) { lGrayChangeNumber = 0; for (i = 0; i < lWidth - 1; i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i +1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } // 记录满足条件的行的位置 if (lGrayChangeNumber >= 10) { // 判断前后满足条件的行是否是相邻 if((iLineLocation == j-1) || (iLineLocation == j-2)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = j; } // 确定满足条件的区域的上下边界 if((iLineNumber >=20) && (iLineNumber <=100)) { iTopLine = iLineLocation+10; iLowLine = iLineLocation - 30; break; } } iLineLocation = 0; iLineNumber = 0; iLeftLine = 0; iRightLine = 0; for (i = 0;i < lWidth ;i++) { lGrayChangeNumber = 0; for(j = iLowLine;j < iTopLine ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * (j+1) + i ; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; // TRACE("%d\t",lGrayChangeNumber); } } if (lGrayChangeNumber >= 2) { // 判断前后满足条件的是否是相邻 if((iLineLocation == i-1) && (iLineLocation >= i-20)) { iLineNumber++; } // 记录满足条件的行的新位置 iLineLocation = i; // TRACE("%d\t",lGrayChangeNumber); } // 确定满足条件的区域的左右边界 if((iLineNumber >=80) && (iLineNumber <=150)) { iLeftLine = iLineLocation -90; iRightLine = iLeftLine + 140; // TRACE("%d\t",i); break; } } int q=0; for (j = iLowLine; j < iTopLine; j++) { for (i = iLeftLine; i < iRightLine; i++) { lpSrc = (char *)lpDIBBits + lLineBytes * j + i; lpDst = (char *)lpNewDIBBits + lNewLineBytes * (j - iLowLine) + (i - iLeftLine); *lpDst = *lpSrc; } } // for (j = 0; j < 40; j++) // { // for(i = 0; i < 140; i++) // { // // lpSrc = (char *)lpNewDIBBits + lNewLineBytes * j + i; // lpDst = (char *)lpDIBBits + lLineBytes * j + i; // *lpDst = *lpSrc; // } // } // 传递车牌位置 int iPlatePosition[4] = {0,0,0,0}; iPlatePosition[0] = iTopLine; iPlatePosition[1] = iLowLine; iPlatePosition[2] = iLeftLine; iPlatePosition[3] = iRightLine; pPlatePosi = &iPlatePosition[0]; // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lNewHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return pPlatePosi; } /************************************************************************* * * 函数名称: * CharacterUnit() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * int iWidht - 归一化字符的宽度 * int iHeight - 归一化字符的高度 * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对车牌字符图像进行归一化处理。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI CharacterUnit(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; // 指向缓存图像的指针 unsigned char* lpDst; // 指向缓存DIB图像的指针 unsigned char* lpNewDIBBits; HLOCAL hNewDIBBits; // 分割后图像的宽度和高度 // LONG lNewWidth = 7 * 15; // LONG lNewHeight = lHeight; //循环变量 long i; long j; long lRow; long lLine; // 图像中每列灰度值为255的个数 long lWhiteGrayNumber; // 像素的灰度值 unsigned char pixelvalue; // 车牌字符所在的列的最左边位置 int iCharLeftRow; // 车牌字符所在的列的最右边位置 int iCharRightRow; // 标志位1,flag1=1时表示开始标志一个字符的位置 int flag1; // 标志位2,flag2=1时表示找到一个字符 int flag2; // 标志这是第几个字符 int iCharNum; // 用于进行字符数据的复制 int iCharLinePixel; // 图像每行的字节数 LONG lLineBytes; // 新图像每行的字节数 LONG lNewLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lNewLineBytes = WIDTHBYTES( lWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lHeight); // 在此分配的内存的大小将来要改变 if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (unsigned char* )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (unsigned char*)lpNewDIBBits; memset(lpDst, (BYTE)0, lNewLineBytes * lHeight); iCharLeftRow = 0; iCharRightRow = 0; flag1 = 1; flag2 = 0; iCharNum = 0; for (lRow = 0;lRow < lWidth ;lRow++) { lWhiteGrayNumber = 0; for(lLine = 0;lLine < lHeight ;lLine++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow; pixelvalue = (unsigned char)*lpSrc; if (pixelvalue == 255) { lWhiteGrayNumber++; // TRACE("%d\t",lWhiteGrayNumber); } } // 寻找字符左边起始列 if ((lWhiteGrayNumber >= 2)&&(flag1 == 1)) { flag1 = 0; iCharLeftRow = lRow; } // 寻找字符右边的终止列 if ((lWhiteGrayNumber <= 2)&&(flag1 == 0)) { iCharRightRow = lRow; flag1 = 1; flag2 = 1; } // 找到一个字符,复制 if(((iCharRightRow - iCharLeftRow) > 7)&&(flag2 == 1)) { iCharNum++; for (j = 0; j < lHeight; j++) { iCharLinePixel = 0; for (i = iCharLeftRow - 1; i < iCharRightRow + 1; i++) { lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i; // lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + i;//20 * (iCharNum - 1) + a; lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + (int)(lWidth / 7) * (iCharNum - 1) + iCharLinePixel; // *lpDst = (unsigned char)255; *lpDst = *lpSrc; iCharLinePixel++; } } flag2 = 0; } if(iCharNum == 7) { break; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); return TRUE; } /************************************************************************* * * 函数名称: * CharacterUnit() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * int iWidht - 归一化字符的宽度 * int iHeight - 归一化字符的高度 * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对车牌字符图像进行归一化处理。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI CharacterUnit1(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, int iWidth, int iHeight) { /* // 指向源图像的指针 unsigned char* lpSrc; // 指向缓存图像的指针 unsigned char* lpDst; // 指向缓存DIB图像的指针 unsigned char* lpNewDIBBits; HLOCAL hNewDIBBits; // 分割后图像的宽度和高度 // LONG lNewWidth = 7 * 15; // LONG lNewHeight = lHeight; //循环变量 long i; long j; long lRow; long lLine; // 图像中每行灰度值为255的个数 long lWhiteGrayNumber; // 像素的灰度值 unsigned char pixelvalue; // 车牌字符所在行的最下边位置 int iCharTopRow; // 车牌字符所在的行的最上边位置 int iCharLowRow; // 标志位1,flag1=1时表示开始标志一个字符的位置 int flag1; // 标志位2,flag2=1时表示找到一个字符 int flag2; // 标志这是第几个字符 int iCharNum; // 用于进行字符数据的复制 int iCharLinePixel; // 图像每行的字节数 LONG lLineBytes; // 新图像每行的字节数 LONG lNewLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lNewLineBytes = WIDTHBYTES( lWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lNewLineBytes * lHeight); // 在此分配的内存的大小将来要改变 if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (unsigned char* )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (unsigned char*)lpNewDIBBits; memset(lpDst, (BYTE)0, lNewLineBytes * lHeight); iCharLeftRow = 0; iCharRightRow = 0; flag1 = 1; flag2 = 0; iCharNum = 0; for (lRow = 0;lRow < lWidth ;lRow++) { lWhiteGrayNumber = 0; for(lLine = 0;lLine < lHeight ;lLine++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow; pixelvalue = (unsigned char)*lpSrc; if (pixelvalue == 255) { lWhiteGrayNumber++; // TRACE("%d\t",lWhiteGrayNumber); } } // 寻找字符左边起始列 if ((lWhiteGrayNumber >= 2)&&(flag1 == 1)) { flag1 = 0; iCharLeftRow = lRow; } // 寻找字符右边的终止列 if ((lWhiteGrayNumber <= 2)&&(flag1 == 0)) { iCharRightRow = lRow; flag1 = 1; flag2 = 1; } // 找到一个字符,复制 if(((iCharRightRow - iCharLeftRow) > 7)&&(flag2 == 1)) { iCharNum++; for (j = 0; j < lHeight; j++) { iCharLinePixel = 0; for (i = iCharLeftRow - 1; i < iCharRightRow + 1; i++) { lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i; // lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + i;//20 * (iCharNum - 1) + a; lpDst = (unsigned char*)lpNewDIBBits + lNewLineBytes * j + (int)(lWidth / 7) * (iCharNum - 1) + iCharLinePixel; // *lpDst = (unsigned char)255; *lpDst = *lpSrc; iCharLinePixel++; } } flag2 = 0; } if(iCharNum == 7) { break; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lNewLineBytes * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); */ return TRUE; } BOOL WINAPI BPTrain(int iInputNum, int iMidNum, int iOutputNum) { // 输入层、中间层和输出层的结点数 // 输入层至隐层的权值 double fHidWeight[64][16]; // 隐层至输出层的权值 double fOutWeight[16][10]; // 存储输入数据 int iTranData[10][64]; // 存储隐层的输入状态 double fHidTemp[16]; // 存储隐层的输出 double fHidData[16]; // 存储输出层的输入状态 double fOutTemp[10]; // 存储输出层的输出 double fOutData[10]; // 输出层至隐层的回传误差 double fOutError[10]; // 隐层至输入层的回传误差 double fHidError[16]; // 每一次对10个数字进行训练得到的误差 double fNumError[10][3]; // 输出层教师的取值 double fTeacher[10][10]; // 训练的步长 double fStep = 0.2; // 对某个样本训练结束标志符 bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 bool bAllEnd = FALSE; // 识别结果 // int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值.dat"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值.dat"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // int iNoise; // 存储加入噪声以后的识别数据 int iNoiseData[10][64]; // 用于情况的选择 // int iChoise; // BP网络的初始化 // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效 // srand((unsigned)time( NULL ) ); // 输入层至隐层的权值的初始化(0 - 0.1) for(i = 0; i < 64; i++) { for(j = 0; j < 16; j++) { fHidWeight[i][j] = (double) (rand() / 327670.0); } } // 隐层至输出层的权值的初始化 for(i = 0; i < 16; i++) { for(j = 0; j <10; j++) { fOutWeight[i][j] = (double) (rand() / 327670.0); } } // 教师向量的初始化 for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { if(j==i) fTeacher[i][j] = 1.0; else fTeacher[i][j] = 0.0; } } /////////////////////////////////////////////////////// // 训练 ////// 读入训练数据 ////// if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 64; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%d",&iTranData[i][j]); iNoiseData[i][j] = iTranData[i][j]; } } // 关闭文件 fclose(fpTranData); // cout<<" 结束!"; // AfxMessageBox("\n 第二步:用误差回传算法进行学习。正在进行......"); // 用误差回传算法进行学习 do { // 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字 for(iTranNum = 0; iTranNum < 10; iTranNum++) { do { bSingleEnd = FALSE; icount++; // 计算隐层各结点的值 for(i = 0; i < 16; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 64; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (double)iTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } // 根据传递函数公式求得输出层的输出 fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 计算误差,判断是否结束此样本的训练 fNumError[iTranNum][0] = 0.0; for(i = 0; i < 10; i++) { fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0; } fNumError[iTranNum][1] = fOutWeight[0][0]; if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效 && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) ) bSingleEnd = TRUE; // 实现误差回传 else { // 计算输出层至隐层的回传误差 for(i = 0; i < 10; i++) { fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i]) * fOutData[i] * (1.0 - fOutData[i]); } // 计算隐层至输入层的回传误差 for(i = 0; i < 16; i++) { fHidError[i] = 0.0; for(j = 0; j < 10; j++) { fHidError[i] += fOutError[j] * fOutWeight[i][j] * fHidData[i] * (1.0 - fHidData[i]); } } // 计算隐层至输出层经误差回传修正后新的权值 for(i = 0; i < 16; i++) { for(j = 0;j < 10; j++) { fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i]; } } // 计算输入层至隐层的权值 for(i = 0; i < 64; i++) { for(j = 0; j < 16; j++) { fHidWeight[i][j] += fStep * fHidError[j] * iTranData[iTranNum][i]; } } } }while(bSingleEnd == FALSE); } // 用于判断用同一组权值对10个数字进行训练是否都满足条件 int a = 0; for(i = 0; i < 9; i++) { if(fNumError[i][1] == fNumError[i+1][1]) a++; } if(a==9) bAllEnd = TRUE; else bAllEnd = FALSE; }while(bAllEnd == FALSE); // AfxMessageBox("训练终于结束了!"); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 64; i++) { for(j = 0; j < 16; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpHidWeight,"%10f",fHidWeight[i][j]); } fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f",fOutWeight[i][j]); fprintf(fpOutWeight,"%10f",fOutWeight[i][j]); } fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); return TRUE; } BOOL WINAPI BPTrain13Section(int iInputNum, int iMidNum, int iOutputNum) { // 输入层、中间层和输出层的结点数 // 输入层至隐层的权值 double fHidWeight[13][10]; // 隐层至输出层的权值 double fOutWeight[10][10]; // 存储输入数据 float fTranData[10][13]; // 存储隐层的输入状态 double fHidTemp[10]; // 存储隐层的输出 double fHidData[10]; // 存储输出层的输入状态 double fOutTemp[10]; // 存储输出层的输出 double fOutData[10]; // 输出层至隐层的回传误差 double fOutError[10]; // 隐层至输入层的回传误差 double fHidError[10]; // 每一次对10个数字进行训练得到的误差 double fNumError[10][3]; // 输出层教师的取值 double fTeacher[10][10]; // 训练的步长 double fStep = 0.2; // 对某个样本训练结束标志符 bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 bool bAllEnd = FALSE; // 识别结果 // int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据_13段.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_13段.txt"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_13段.txt"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // BP网络的初始化 // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效 // srand((unsigned)time( NULL ) ); // 输入层至隐层的权值的初始化(0 - 0.1) for(i = 0; i < 13; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] = (double) (rand() / 327670.0); } } // 隐层至输出层的权值的初始化 for(i = 0; i < 10; i++) { for(j = 0; j <10; j++) { fOutWeight[i][j] = (double) (rand() / 327670.0); } } // 教师向量的初始化 for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { if(j==i) fTeacher[i][j] = 1.0; else fTeacher[i][j] = 0.0; } } int q=0; /////////////////////////////////////////////////////// // 训练 ////// 读入训练数据 ////// if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 13; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%f",&fTranData[i][j]); } } // 关闭文件 fclose(fpTranData); // cout<<" 结束!"; // AfxMessageBox("\n 第二步:用误差回传算法进行学习。正在进行......"); // 用误差回传算法进行学习 do { // 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字 for(iTranNum = 0; iTranNum < 10; iTranNum++) { do { bSingleEnd = FALSE; icount++; // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 13; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } // 根据传递函数公式求得输出层的输出 fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 计算误差,判断是否结束此样本的训练 fNumError[iTranNum][0] = 0.0; for(i = 0; i < 10; i++) { fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0; } fNumError[iTranNum][1] = fOutWeight[0][0]; if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效 && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) ) bSingleEnd = TRUE; // 实现误差回传 else { // 计算输出层至隐层的回传误差 for(i = 0; i < 10; i++) { fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i]) * fOutData[i] * (1.0 - fOutData[i]); } // 计算隐层至输入层的回传误差 for(i = 0; i < 10; i++) { fHidError[i] = 0.0; for(j = 0; j < 10; j++) { fHidError[i] += fOutError[j] * fOutWeight[i][j] * fHidData[i] * (1.0 - fHidData[i]); } } // 计算隐层至输出层经误差回传修正后新的权值 for(i = 0; i < 10; i++) { for(j = 0;j < 10; j++) { fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i]; } } // 计算输入层至隐层的权值 for(i = 0; i <13; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i]; } } } }while(bSingleEnd == FALSE); } // 用于判断用同一组权值对10个数字进行训练是否都满足条件 int a = 0; for(i = 0; i < 9; i++) { if(fNumError[i][1] == fNumError[i+1][1]) a++; } float z1=fNumError[0][1] - fNumError[9][1]; if(a==9) bAllEnd = TRUE; else bAllEnd = FALSE; int z2=0; }while(bAllEnd == FALSE); AfxMessageBox("训练终于结束了!"); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 13; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpHidWeight,"%10f",fHidWeight[i][j]); } fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f",fOutWeight[i][j]); fprintf(fpOutWeight,"%10f",fOutWeight[i][j]); } fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); return TRUE; } BOOL WINAPI BPTrain16SectionLetter(int iInputNum, int iMidNum, int iOutputNum) { // 输入层、中间层和输出层的结点数 // 输入层至隐层的权值 double fHidWeight[16][10]; // 隐层至输出层的权值 double fOutWeight[10][26]; // 存储输入数据 float fTranData[26][16]; // 存储隐层的输入状态 double fHidTemp[10]; // 存储隐层的输出 double fHidData[10]; // 存储输出层的输入状态 double fOutTemp[26]; // 存储输出层的输出 double fOutData[26]; // 输出层至隐层的回传误差 double fOutError[26]; // 隐层至输入层的回传误差 double fHidError[10]; // 每一次对10个数字进行训练得到的误差 double fNumError[26][3]; // 输出层教师的取值 double fTeacher[26][26]; // 训练的步长 double fStep = 0.2; // 对某个样本训练结束标志符 bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 bool bAllEnd = FALSE; // 识别结果 // int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据_16段投影字母.txt "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_16段投影字母.txt "; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_16段投影字母.txt "; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // BP网络的初始化 // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效 // srand((unsigned)time( NULL ) ); // 输入层至隐层的权值的初始化(0 - 0.1) for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] = (double) (rand() / 327670.0); } } // 隐层至输出层的权值的初始化 for(i = 0; i < 10; i++) { for(j = 0; j <26; j++) { fOutWeight[i][j] = (double) (rand() / 327670.0); } } // 教师向量的初始化 for(i = 0; i < 26; i++) { for(j = 0; j < 26; j++) { if(j==i) fTeacher[i][j] = 1.0; else fTeacher[i][j] = 0.0; } } int q=0; /////////////////////////////////////////////////////// // 训练 ////// 读入训练数据 ////// if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 26; i++) { for(j = 0; j < 16; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%f",&fTranData[i][j]); } } // 关闭文件 fclose(fpTranData); // cout<<" 结束!"; // AfxMessageBox("\n 第二步:用误差回传算法进行学习。正在进行......"); // 用误差回传算法进行学习 do { // 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字 for(iTranNum = 0; iTranNum < 26; iTranNum++) { do { bSingleEnd = FALSE; icount++; // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 26; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } // 根据传递函数公式求得输出层的输出 fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 计算误差,判断是否结束此样本的训练 fNumError[iTranNum][0] = 0.0; for(i = 0; i < 26; i++) { fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0; } fNumError[iTranNum][1] = fOutWeight[0][0]; if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效 && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) ) bSingleEnd = TRUE; // 实现误差回传 else { // 计算输出层至隐层的回传误差 for(i = 0; i < 26; i++) { fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i]) * fOutData[i] * (1.0 - fOutData[i]); } // 计算隐层至输入层的回传误差 for(i = 0; i < 10; i++) { fHidError[i] = 0.0; for(j = 0; j < 26; j++) { fHidError[i] += fOutError[j] * fOutWeight[i][j] * fHidData[i] * (1.0 - fHidData[i]); } } // 计算隐层至输出层经误差回传修正后新的权值 for(i = 0; i < 10; i++) { for(j = 0;j < 26; j++) { fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i]; } } // 计算输入层至隐层的权值 for(i = 0; i <16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i]; } } } }while(bSingleEnd == FALSE); } // 用于判断用同一组权值对10个数字进行训练是否都满足条件 int a = 0; for(i = 0; i < 25; i++) { if(fNumError[i][1] == fNumError[i+1][1]) a++; } float zzz=fNumError[0][1]-fNumError[25][1]; if(a==25) bAllEnd = TRUE; else bAllEnd = FALSE; int zz=0; }while(bAllEnd == FALSE); AfxMessageBox("训练终于结束了!"); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"w+"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpHidWeight,"%10f",fHidWeight[i][j]); } fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"w+"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 26; j++) { // fprintf(fpOutWeight,"%f",fOutWeight[i][j]); fprintf(fpOutWeight,"%10f",fOutWeight[i][j]); } fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); return TRUE; } BOOL WINAPI BPTrain16SectionNumber(int iInputNum, int iMidNum, int iOutputNum) { // 输入层、中间层和输出层的结点数 // 输入层至隐层的权值 double fHidWeight[16][10]; // 隐层至输出层的权值 double fOutWeight[10][10]; // 存储输入数据 float fTranData[10][16];//float fTranData[100][16],每个数字有10个训练样本 // 存储隐层的输入状态 double fHidTemp[10]; // 存储隐层的输出 double fHidData[10]; // 存储输出层的输入状态 double fOutTemp[10]; // 存储输出层的输出 double fOutData[10]; // 输出层至隐层的回传误差 double fOutError[10]; // 隐层至输入层的回传误差 double fHidError[10]; // 每一次对10个数字进行训练得到的误差 double fNumError[10][3];//double fNumError[100][3]; // 输出层教师的取值 double fTeacher[10][10];// // 训练的步长 double fStep = 0.2; // 对某个样本训练结束标志符 bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 bool bAllEnd = FALSE; // 识别结果 // int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据_16段投影数字.txt "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_16段投影数字.txt"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_16段投影数字.txt"; // 循环变量 int i,j; // 正在训练或识别的数据 int iTranNum; // 正在训练或识别的数字 // int iTranNumber; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // BP网络的初始化 // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效 // srand((unsigned)time( NULL ) ); // 输入层至隐层的权值的初始化(0 - 0.1) for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] = (double) (rand() / 327670.0); } } // 隐层至输出层的权值的初始化 for(i = 0; i < 10; i++) { for(j = 0; j <10; j++) { fOutWeight[i][j] = (double) (rand() / 327670.0); } } // 教师向量的初始化 for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { if(j==i) fTeacher[i][j] = 1.0; else fTeacher[i][j] = 0.0; } } int q=0; /////////////////////////////////////////////////////// // 训练 ////// 读入训练数据 ////// if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++)//for(i = 0; i < 100; i++) { for(j = 0; j < 16; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%f",&fTranData[i][j]); } } // 关闭文件 fclose(fpTranData); // cout<<" 结束!"; // AfxMessageBox("\n 第二步:用误差回传算法进行学习。正在进行......"); // 用误差回传算法进行学习 do { // 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字 for(iTranNum = 0; iTranNum < 10; iTranNum++)//for(iTranNum = 0; iTranNum < 100; iTranNum++) { int z=0; do { bSingleEnd = FALSE; icount++; // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } // 根据传递函数公式求得输出层的输出 fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 计算误差,判断是否结束此样本的训练 fNumError[iTranNum][0] = 0.0; for(i = 0; i < 10; i++) { fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0; } fNumError[iTranNum][1] = fOutWeight[0][0]; if((fNumError[iTranNum][0] < 0.1)// 如您想提高训练的效果,请下行注释有效 && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) ) bSingleEnd = TRUE; // 实现误差回传 else { // 计算输出层至隐层的回传误差 for(i = 0; i < 10; i++) { fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i]) * fOutData[i] * (1.0 - fOutData[i]); } // 计算隐层至输入层的回传误差 for(i = 0; i < 10; i++) { fHidError[i] = 0.0; for(j = 0; j < 10; j++) { fHidError[i] += fOutError[j] * fOutWeight[i][j] * fHidData[i] * (1.0 - fHidData[i]); } } // 计算隐层至输出层经误差回传修正后新的权值 for(i = 0; i < 10; i++) { for(j = 0;j < 10; j++) { fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i]; } } // 计算输入层至隐层的权值 for(i = 0; i <16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i]; } } } }while(bSingleEnd == FALSE); } // 用于判断用同一组权值对10个数字进行训练是否都满足条件 int a = 0; for(i = 0; i < 9; i++)//for(i = 0; i < 99; i++) { if(fNumError[i][1] == fNumError[i+1][1]) a++; } float za=fNumError[0][1] - fNumError[9][1]; if(a==9)//if(a==99) bAllEnd = TRUE; else bAllEnd = FALSE; }while(bAllEnd == FALSE); AfxMessageBox("训练终于结束了!"); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpHidWeight,"%10f",fHidWeight[i][j]); } fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f",fOutWeight[i][j]); fprintf(fpOutWeight,"%10f",fOutWeight[i][j]); } fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); return TRUE; } BOOL WINAPI BPTrain16SectionNumber2(int iInputNum, int iMidNum, int iOutputNum) { //#define TRAINDATANUM 100 // 用于训练的数字样本的个数,应为10的整数倍 //#define TRAINDATALET 260 // 用于训练的字母样本的个数,应为26的整数倍 // 输入层、中间层和输出层的结点数 // 输入层至隐层的权值 double fHidWeight[16][10]; // 隐层至输出层的权值 double fOutWeight[10][10]; // 存储输入数据 float fTranData[TRAINDATANUM][16];//float fTranData[100][16],每个数字有10个训练样本 // 存储隐层的输入状态 double fHidTemp[10]; // 存储隐层的输出 double fHidData[10]; // 存储输出层的输入状态 double fOutTemp[10]; // 存储输出层的输出 double fOutData[10]; // 输出层至隐层的回传误差 double fOutError[10]; // 隐层至输入层的回传误差 double fHidError[10]; // 每一次对10个数字进行训练得到的误差 double fNumError[TRAINDATANUM][3];//double fNumError[100][3]; // 输出层教师的取值 double fTeacher[10][10];// // 训练的步长 double fStep = 0.2; // 对某个样本训练结束标志符 bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 bool bAllEnd = FALSE; // 识别结果 // int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据_16段投影数字.txt "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_16段投影数字.txt"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_16段投影数字.txt"; // 循环变量 int i,j; // 正在训练或识别的数据 int iTranNum; // 正在训练或识别的数字 int iTranNumber; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // BP网络的初始化 // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效 // srand((unsigned)time( NULL ) ); // 输入层至隐层的权值的初始化(0 - 0.1) for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] = (double) (rand() / 327670.0); } } // 隐层至输出层的权值的初始化 for(i = 0; i < 10; i++) { for(j = 0; j <10; j++) { fOutWeight[i][j] = (double) (rand() / 327670.0); } } // 教师向量的初始化 for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { if(j==i) fTeacher[i][j] = 1.0; else fTeacher[i][j] = 0.0; } } int q=0; /////////////////////////////////////////////////////// // 训练 ////// 读入训练数据 ////// if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < TRAINDATANUM; i++)//for(i = 0; i < 100; i++) { for(j = 0; j < 16; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%f",&fTranData[i][j]); } } // 关闭文件 fclose(fpTranData); // cout<<" 结束!"; // AfxMessageBox("\n 第二步:用误差回传算法进行学习。正在进行......"); // 用误差回传算法进行学习 do { // 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字 for(iTranNum = 0; iTranNum < TRAINDATANUM; iTranNum++)//for(iTranNum = 0; iTranNum < 100; iTranNum++) { iTranNumber=iTranNum/10; int z=0; do { bSingleEnd = FALSE; icount++; // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } // 根据传递函数公式求得输出层的输出 fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 计算误差,判断是否结束此样本的训练 fNumError[iTranNum][0] = 0.0; for(i = 0; i < 10; i++) { fNumError[iTranNum][0] += ( (fTeacher[iTranNumber][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0; } fNumError[iTranNum][1] = fOutWeight[0][0]; if((fNumError[iTranNum][0] < 0.1)// 如您想提高训练的效果,请下行注释有效 && ( (fOutData[iTranNumber] - 1.0) * (fOutData[iTranNumber] - 1.0) < 0.01 ) ) bSingleEnd = TRUE; // 实现误差回传 else { // 计算输出层至隐层的回传误差 for(i = 0; i < 10; i++) { fOutError[i] = (fTeacher[iTranNumber][i]-fOutData[i]) * fOutData[i] * (1.0 - fOutData[i]); } // 计算隐层至输入层的回传误差 for(i = 0; i < 10; i++) { fHidError[i] = 0.0; for(j = 0; j < 10; j++) { fHidError[i] += fOutError[j] * fOutWeight[i][j] * fHidData[i] * (1.0 - fHidData[i]); } } // 计算隐层至输出层经误差回传修正后新的权值 for(i = 0; i < 10; i++) { for(j = 0;j < 10; j++) { fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i]; } } // 计算输入层至隐层的权值 for(i = 0; i <16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i]; } } } }while(bSingleEnd == FALSE); } // 用于判断用同一组权值对10个数字进行训练是否都满足条件 int a = 0; for(i = 0; i < TRAINDATANUM-1; i++)//for(i = 0; i < 99; i++) { if(fNumError[i][1] == fNumError[i+1][1]) a++; } if(a==TRAINDATANUM-1)//if(a==99) bAllEnd = TRUE; else bAllEnd = FALSE; }while(bAllEnd == FALSE); AfxMessageBox("训练终于结束了!"); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpHidWeight,"%10f",fHidWeight[i][j]); } fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f",fOutWeight[i][j]); fprintf(fpOutWeight,"%10f",fOutWeight[i][j]); } fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); return TRUE; } BOOL WINAPI BPTrainStruct(int iInputNum, int iMidNum, int iOutputNum) { // 输入层、中间层和输出层的结点数 // 输入层至隐层的权值 double fHidWeight[16][10]; // 隐层至输出层的权值 double fOutWeight[10][10]; // 存储输入数据 float fTranData[10][16]; // 存储隐层的输入状态 double fHidTemp[10]; // 存储隐层的输出 double fHidData[10]; // 存储输出层的输入状态 double fOutTemp[10]; // 存储输出层的输出 double fOutData[10]; // 输出层至隐层的回传误差 double fOutError[10]; // 隐层至输入层的回传误差 double fHidError[10]; // 每一次对10个数字进行训练得到的误差 double fNumError[10][3]; // 输出层教师的取值 double fTeacher[10][10]; // 训练的步长 double fStep = 0.2; // 对某个样本训练结束标志符 bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 bool bAllEnd = FALSE; // 识别结果 // int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据_微特征.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_微特征.dat"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_微特征.dat"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // BP网络的初始化 // 如果您想在每次运行时可得到不同的随机数,请使下行注释有效 // srand((unsigned)time( NULL ) ); // 输入层至隐层的权值的初始化(0 - 0.1) for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] = (double) (rand() / 327670.0); } } // 隐层至输出层的权值的初始化 for(i = 0; i < 10; i++) { for(j = 0; j <10; j++) { fOutWeight[i][j] = (double) (rand() / 327670.0); } } // 教师向量的初始化 for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { if(j==i) fTeacher[i][j] = 1.0; else fTeacher[i][j] = 0.0; } } int q=0; /////////////////////////////////////////////////////// // 训练 ////// 读入训练数据 ////// if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 16; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%f",&fTranData[i][j]); } } // 关闭文件 fclose(fpTranData); // cout<<" 结束!"; // AfxMessageBox("\n 第二步:用误差回传算法进行学习。正在进行......"); // 用误差回传算法进行学习 do { // 每次训练都用10个数字重新进行学习,i代表(0-9)10个数字 for(iTranNum = 0; iTranNum < 10; iTranNum++) { do { bSingleEnd = FALSE; icount++; // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (double)fTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } // 根据传递函数公式求得输出层的输出 fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 计算误差,判断是否结束此样本的训练 fNumError[iTranNum][0] = 0.0; for(i = 0; i < 10; i++) { fNumError[iTranNum][0] += ( (fTeacher[iTranNum][i] - fOutData[i]) * (fTeacher[iTranNum][i] - fOutData[i]) ) / 2.0; } fNumError[iTranNum][1] = fOutWeight[0][0]; if((fNumError[iTranNum][0] < 0.01)// 如您想提高训练的效果,请下行注释有效 && ( (fOutData[iTranNum] - 1.0) * (fOutData[iTranNum] - 1.0) < 0.01 ) ) bSingleEnd = TRUE; // 实现误差回传 else { // 计算输出层至隐层的回传误差 for(i = 0; i < 10; i++) { fOutError[i] = (fTeacher[iTranNum][i]-fOutData[i]) * fOutData[i] * (1.0 - fOutData[i]); } // 计算隐层至输入层的回传误差 for(i = 0; i < 10; i++) { fHidError[i] = 0.0; for(j = 0; j < 10; j++) { fHidError[i] += fOutError[j] * fOutWeight[i][j] * fHidData[i] * (1.0 - fHidData[i]); } } // 计算隐层至输出层经误差回传修正后新的权值 for(i = 0; i < 10; i++) { for(j = 0;j < 10; j++) { fOutWeight[i][j] += fStep * fOutError[j] * fHidData[i]; } } // 计算输入层至隐层的权值 for(i = 0; i <16; i++) { for(j = 0; j < 10; j++) { fHidWeight[i][j] += fStep * fHidError[j] * fTranData[iTranNum][i]; } } } }while(bSingleEnd == FALSE); } // 用于判断用同一组权值对10个数字进行训练是否都满足条件 int a = 0; for(i = 0; i < 9; i++) { if(fNumError[i][1] == fNumError[i+1][1]) a++; } if(a==9) bAllEnd = TRUE; else bAllEnd = FALSE; }while(bAllEnd == FALSE); // AfxMessageBox("训练终于结束了!"); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpHidWeight,"%10f",fHidWeight[i][j]); } fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"w"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f",fOutWeight[i][j]); fprintf(fpOutWeight,"%10f",fOutWeight[i][j]); } fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); return TRUE; } BOOL WINAPI BPReco() { // 输入层至隐层的权值 float fHidWeight[64][16]; // 隐层至输出层的权值 float fOutWeight[16][10]; // 存储输入数据 int iTranData[10][64]; // 存储隐层的输入状态 float fHidTemp[16]; // 存储隐层的输出 float fHidData[16]; // 存储输出层的输入状态 float fOutTemp[10]; // 存储输出层的输出 float fOutData[10]; // 输出层至隐层的回传误差 // double fOutError[10]; // 隐层至输入层的回传误差 // double fHidError[16]; // 每一次对10个数字进行训练得到的误差 // double fNumError[10][3]; // 输出层教师的取值 // double fTeacher[10][10]; // 训练的步长 float fStep = 0.2; // 对某个样本训练结束标志符 // bool bSingleEnd = FALSE; // 对全部样本训练结束标志符 // bool bAllEnd = FALSE; // 识别结果 int iRecoResult; // 识别率 // int iRecoRate; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值.dat"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值.dat"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // int iNoise; // 存储加入噪声以后的识别数据 // int iNoiseData[10][64]; // 用于情况的选择 // int iChoise; if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 64; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%d",&iTranData[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } } // 关闭文件 fclose(fpTranData); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpHidWeight, 0L, SEEK_SET ); for(i = 0; i < 64; i++) { for(j = 0; j < 16; j++) { // fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]); fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]); } // fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpOutWeight, 0L, SEEK_SET ); for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]); fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } // fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); /////////////////////////////////////////////////////// // 识别 // do // { //////////////////////////////////////////////////// // 加入随机噪声 // iNoise = 0 ; // iRecoRate = 0; // for(i=0;i<10;i++) // { // for(j=0;j<64;j++) // { // 每次识别加入的误差都是在原始数据基础上加上的 // iNoiseData[i][j] = iTranData[i][j]; // if((rand()/327.67)<iNoise) // iNoiseData[i][j] = 1 - iNoiseData[i][j]; // } // } for(iTranNum = 0; iTranNum < 10; iTranNum++) { // 计算隐层各结点的值 for(i = 0; i < 16; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 64; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (float)iTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 根据输出确定识别结果 float fTemp = 0.0; int iMax = 0; for(i = 0; i < 10; i++) { if(fOutData[i] > fTemp) { fTemp = fOutData[i]; // 判断准则:输出最大的结点的标号 iMax = i; } } iRecoResult = iMax; TRACE("*** %d ***\n",iRecoResult); // TRACE("*** %10f ***\n",fOutWeight[0][0]); // cout<<" 识别结果为:"<<iRecoResult; // if(iRecoResult == iTranNum) // iRecoRate += 10; } // cout<<" 识别率为:"<<iRecoRate<<" %"; // if(iRecoRate == 100) // cout<<" 太棒了!"; // else if(iRecoRate >= 80) // cout<<" 嗯!不错! "; // else if(iRecoRate >= 60) // cout<<" 还行!还行!"; // else // cout<<" 天哪!重新开始吧!"; // // cout<<"\n*** 改变噪声比例,继续识别,请按数字“1” 结束此程序的运行,请按下数字“0”:***"; // iChoise = 3; // cin>>iChoise; // }while(iChoise==1); // if(iChoise==0) // { // cout<<endl; // cout<<"\n 谢谢您使用该软件。";//由于时间短促(我只写了两天)它还有许多不足,如:采用的"; // cout<<"\n是最基本的算法、训练的速率不够高、网络的容错性一般,另外这是个DOS程序,还没有"; // cout<<"\n实现Windows版本(呵呵,这是我课题要做的一部分)。所以,希望各位师弟师妹提出"; // cout<<"请您提出宝贵意见,并加以完善! 再见!(请按任意键结束)"; // cout<<"\n 作者:王建 2001/6/27 "; // cout<<endl; // } // else // cout<<endl<<"很抱歉,你作出了错误的选择,这将导致程序的结束!(请按任意键继续)"<<endl; return TRUE; } unsigned char WINAPI BPReco13Section(float* pRecoData) { // 输入层至隐层的权值 float fHidWeight[13][10]; // 隐层至输出层的权值 float fOutWeight[10][10]; // 存储输入数据 float fTranData[10][13]; // 存储隐层的输入状态 float fHidTemp[10]; // 存储隐层的输出 float fHidData[10]; // 存储输出层的输入状态 float fOutTemp[10]; // 存储输出层的输出 float fOutData[10]; // 训练的步长 float fStep = 0.2; unsigned char iRecoResult; // 存储识别数据 float fRecoData[13]; // 指向存有训练数据的文件的指针、文件名的字符串 // FILE *fpTranData; // char *TranDataFileName = "训练数据_13段.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_13段.dat"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_13段.dat"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // int iNoise; // 存储加入噪声以后的识别数据 // int iNoiseData[10][64]; // 用于情况的选择 // int iChoise; // if((fpTranData = fopen(TranDataFileName,"r"))==NULL) // { // AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); // return 0; // } for(i = 0; i < 13; i++) { fRecoData[i] = *pRecoData; pRecoData++; // for(j = 0; j < 13; j++) // { // 将训练数据读入训练数据数组中 // fscanf(fpTranData,"%f",&fTranData[i][j]); // iNoiseData[i][j] = iTranData[i][j]; // } } // 关闭文件 // fclose(fpTranData); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpHidWeight, 0L, SEEK_SET ); for(i = 0; i < 13; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]); fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]); } // fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpOutWeight, 0L, SEEK_SET ); for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]); fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } // fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); /////////////////////////////////////////////////////// // 识别 // for(iTranNum = 0; iTranNum < 10; iTranNum++) // { // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 13; j++) // j代表输入层的各个结点 { // fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ?????? fHidTemp[i] += fHidWeight[j][i] * (float)fRecoData[j]; } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 根据输出确定识别结果 float fTemp = 0.0; int iMax = 0; for(i = 0; i < 10; i++) { if(fOutData[i] > fTemp) { fTemp = fOutData[i]; // 判断准则:输出最大的结点的标号 iMax = i; } } iRecoResult = (unsigned char)iMax + 48; // TRACE("*** %d ***\n",iRecoResult); // } return iRecoResult; } unsigned char WINAPI BPReco16SectionNumber(float* pRecoData) { // 输入层至隐层的权值 float fHidWeight[16][10]; // 隐层至输出层的权值 float fOutWeight[10][10]; // 存储输入数据 float fTranData[10][16]; // 存储隐层的输入状态 float fHidTemp[10]; // 存储隐层的输出 float fHidData[10]; // 存储输出层的输入状态 float fOutTemp[10]; // 存储输出层的输出 float fOutData[10]; // 训练的步长 float fStep = 0.2; unsigned char iRecoResult; // 存储识别数据 float fRecoData[16]; // 指向存有训练数据的文件的指针、文件名的字符串 // FILE *fpTranData; // char *TranDataFileName = "训练数据_13段.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_16段投影数字.txt"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_16段投影数字.txt"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // int iNoise; // 存储加入噪声以后的识别数据 // int iNoiseData[10][64]; // 用于情况的选择 // int iChoise; // if((fpTranData = fopen(TranDataFileName,"r"))==NULL) // { // AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); // return 0; // } for(i = 0; i < 16; i++) { fRecoData[i] = *pRecoData; pRecoData++; // for(j = 0; j < 13; j++) // { // 将训练数据读入训练数据数组中 // fscanf(fpTranData,"%f",&fTranData[i][j]); // iNoiseData[i][j] = iTranData[i][j]; // } } // 关闭文件 // fclose(fpTranData); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpHidWeight, 0L, SEEK_SET ); for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]); fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]); } // fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpOutWeight, 0L, SEEK_SET ); for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]); fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } // fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); /////////////////////////////////////////////////////// // 识别 // for(iTranNum = 0; iTranNum < 10; iTranNum++) // { // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { // fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ?????? fHidTemp[i] += fHidWeight[j][i] * (float)fRecoData[j]; } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 根据输出确定识别结果 float fTemp = 0.0; int iMax = 0; for(i = 0; i < 10; i++) { if(fOutData[i] > fTemp) { fTemp = fOutData[i]; // 判断准则:输出最大的结点的标号 iMax = i; } } iRecoResult = (unsigned char)iMax + 48; // TRACE("*** %d ***\n",iRecoResult); // } return iRecoResult; } unsigned char WINAPI BPReco16SectionLetter(float* pRecoData) { // 输入层至隐层的权值 float fHidWeight[16][10]; // 隐层至输出层的权值 float fOutWeight[10][26]; // 存储输入数据 // float fTranData[10][16]; // 存储隐层的输入状态 float fHidTemp[10]; // 存储隐层的输出 float fHidData[10]; // 存储输出层的输入状态 float fOutTemp[26]; // 存储输出层的输出 float fOutData[26]; // 识别结果 unsigned char iRecoResult; // 存储识别数据 float fRecoData[16]; // 指向存有训练数据的文件的指针、文件名的字符串 // FILE *fpTranData; // char *TranDataFileName = "训练数据_13段.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_16段投影字母.txt"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_16段投影字母.txt"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; for(i = 0; i < 16; i++) { fRecoData[i] = *pRecoData; pRecoData++; } // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpHidWeight, 0L, SEEK_SET ); for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]); fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]); } // fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpOutWeight, 0L, SEEK_SET ); for(i = 0; i < 10; i++) { for(j = 0; j < 26; j++) { // fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]); fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } // fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); /////////////////////////////////////////////////////// // 识别 // for(iTranNum = 0; iTranNum < 10; iTranNum++) // { // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { // fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ?????? fHidTemp[i] += fHidWeight[j][i] * (float)fRecoData[j]; } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 26; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 根据输出确定识别结果 float fTemp = 0.0; int iMax = 0; for(i = 0; i < 26; i++) { if(fOutData[i] > fTemp) { fTemp = fOutData[i]; // 判断准则:输出最大的结点的标号 iMax = i; } } iRecoResult = (unsigned char)iMax + 65; // TRACE("*** %d ***\n",iRecoResult); // } return iRecoResult; } BOOL WINAPI BPRecoStruct() { // 输入层至隐层的权值 float fHidWeight[16][10]; // 隐层至输出层的权值 float fOutWeight[10][10]; // 存储输入数据 float fTranData[10][16]; // 存储隐层的输入状态 float fHidTemp[10]; // 存储隐层的输出 float fHidData[10]; // 存储输出层的输入状态 float fOutTemp[10]; // 存储输出层的输出 float fOutData[10]; // 训练的步长 float fStep = 0.2; int iRecoResult; // 指向存有训练数据的文件的指针、文件名的字符串 FILE *fpTranData; char *TranDataFileName = "训练数据_微特征.dat "; // 指向存有已训练好的输入层至隐层的权值的文件的指针 FILE *fpHidWeight; char *HidWeightName = "隐层权值_微特征.dat"; // 指向存有已训练好的隐层至输出层的权值的文件的指针 FILE *fpOutWeight; char *OutWeightName = "输出层权值_微特征.dat"; // 循环变量 int i,j; // 正在训练或识别的数字 int iTranNum; // 记录训练次数 int icount=0; // 要加入的随机噪声的百分比 // int iNoise; // 存储加入噪声以后的识别数据 // int iNoiseData[10][64]; // 用于情况的选择 // int iChoise; if((fpTranData = fopen(TranDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 16; j++) { // 将训练数据读入训练数据数组中 fscanf(fpTranData,"%f",&fTranData[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } } // 关闭文件 fclose(fpTranData); ///////////////////////////////////////////////////////// // 存储训练好的权值 // 存储输入层至隐层的权值 if((fpHidWeight = fopen(HidWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpHidWeight, 0L, SEEK_SET ); for(i = 0; i < 16; i++) { for(j = 0; j < 10; j++) { // fprintf(fpHidWeight,"%f\t",fHidWeight[i][j]); fscanf(fpHidWeight,"%10f",&fHidWeight[i][j]); } // fprintf(fpHidWeight,"\n",""); } fclose(fpHidWeight); // 存储隐层至输出层的权值 if((fpOutWeight = fopen(OutWeightName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } fseek( fpOutWeight, 0L, SEEK_SET ); for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { // fprintf(fpOutWeight,"%f\t",fOutWeight[i][j]); fscanf(fpOutWeight,"%10f",&fOutWeight[i][j]); // iNoiseData[i][j] = iTranData[i][j]; } // fprintf(fpOutWeight,"\n",""); } fclose(fpOutWeight); /////////////////////////////////////////////////////// // 识别 for(iTranNum = 0; iTranNum < 10; iTranNum++) { // 计算隐层各结点的值 for(i = 0; i < 10; i++) // i代表隐层的各个结点 { fHidTemp[i] = 0.0; for(j = 0; j < 16; j++) // j代表输入层的各个结点 { fHidTemp[i] += fHidWeight[j][i] * (float)fTranData[iTranNum][j]; // ?????? } // 根据传递函数公式求得隐层的输出 fHidData[i] = 1.0 / ( 1.0 + exp(-fHidTemp[i]) ); } // 计算输出层各结点的值 for(i = 0; i < 10; i++) // i代表输出层的各个结点 { fOutTemp[i] = 0.0; for(j = 0; j < 10; j++) // j代表隐层的各个结点 { fOutTemp[i] += fOutWeight[j][i] * fHidData[j]; } fOutData[i] = 1.0 / ( 1.0 + exp(-fOutTemp[i]) ); } // 根据输出确定识别结果 float fTemp = 0.0; int iMax = 0; for(i = 0; i < 10; i++) { if(fOutData[i] > fTemp) { fTemp = fOutData[i]; // 判断准则:输出最大的结点的标号 iMax = i; } } iRecoResult = iMax; TRACE("*** %d ***\n",iRecoResult); } return TRUE; } /************************************************************************* * * 函数名称: * ContourDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行轮廓提取运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI ContourDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; unsigned char n,e,s,w,ne,se,nw,sw; //像素值 unsigned char pixel; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); for(j = 1; j <lHeight-1; j++) { for(i = 1;i <lWidth-1; i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lWidth * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lWidth * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 // if(pixel != 255 && pixel != 0) // return FALSE; if(pixel == 0) { *lpDst = (unsigned char)0; nw = (unsigned char)*(lpSrc + lWidth -1); n = (unsigned char)*(lpSrc + lWidth ); ne = (unsigned char)*(lpSrc + lWidth +1); w = (unsigned char)*(lpSrc -1); e = (unsigned char)*(lpSrc +1); sw = (unsigned char)*(lpSrc - lWidth -1); s = (unsigned char)*(lpSrc - lWidth ); se = (unsigned char)*(lpSrc - lWidth +1); //如果相邻的八个点都是黑点 if(nw+n+ne+w+e+sw+s+se==0) { *lpDst = (unsigned char)255; } } } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * TraceDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行轮廓跟踪运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI TraceDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // 图像每行的字节数 LONG lLineBytes; //循环变量 long i; long j; //像素值 unsigned char pixel; //是否找到起始点及回到起始点 bool bFindStartPoint; //是否扫描到一个边界点 bool bFindPoint; //起始边界点与当前边界点 Point StartPoint,CurrentPoint; //八个方向和起始扫描方向 int Direction[8][2]={{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0}}; int BeginDirect; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lLineBytes * lHeight); //先找到最左上方的边界点 bFindStartPoint = false; for (j = 0;j < lHeight && !bFindStartPoint;j++) { for(i = 0;i < lWidth && !bFindStartPoint;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; if(pixel == 0) { bFindStartPoint = true; StartPoint.Height = j; StartPoint.Width = i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + i; *lpDst = (unsigned char)0; } } } //由于起始点是在左下方,故起始扫描沿左上方向 BeginDirect = 0; //跟踪边界 bFindStartPoint = false; //从初始点开始扫描 CurrentPoint.Height = StartPoint.Height; CurrentPoint.Width = StartPoint.Width; while(!bFindStartPoint) { bFindPoint = false; while(!bFindPoint) { //沿扫描方向查看一个像素 lpSrc = (char *)lpDIBBits + lLineBytes * ( CurrentPoint.Height + Direction[BeginDirect][1]) + (CurrentPoint.Width + Direction[BeginDirect][0]); pixel = (unsigned char)*lpSrc; if(pixel == 0) { bFindPoint = true; CurrentPoint.Height = CurrentPoint.Height + Direction[BeginDirect][1]; CurrentPoint.Width = CurrentPoint.Width + Direction[BeginDirect][0]; if(CurrentPoint.Height == StartPoint.Height && CurrentPoint.Width == StartPoint.Width) { bFindStartPoint = true; } lpDst = (char *)lpNewDIBBits + lLineBytes * CurrentPoint.Height + CurrentPoint.Width; *lpDst = (unsigned char)0; //扫描的方向逆时针旋转两格 BeginDirect--; if(BeginDirect == -1) BeginDirect = 7; BeginDirect--; if(BeginDirect == -1) BeginDirect = 7; } else { //扫描方向顺时针旋转一格 BeginDirect++; if(BeginDirect == 8) BeginDirect = 0; } } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * FFT() * * 参数: * complex<double> * TD - 指向时域数组的指针 * complex<double> * FD - 指向频域数组的指针 * r -2的幂数,即迭代次数 * * 返回值: * 无。 * * 说明: * 该函数用来实现快速付立叶变换。 * ************************************************************************/ VOID WINAPI FFT(complex<double> * TD, complex<double> * FD, int r) { // 付立叶变换点数 LONG count; // 循环变量 int i,j,k; // 中间变量 int bfsize,p; // 角度 double angle; complex<double> *W,*X1,*X2,*X; // 计算付立叶变换点数 count = 1 << r; // 分配运算所需存储器 W = new complex<double>[count / 2]; X1 = new complex<double>[count]; X2 = new complex<double>[count]; // 计算加权系数 for(i = 0; i < count / 2; i++) { angle = -i * PI * 2 / count; W[i] = complex<double> (cos(angle), sin(angle)); } // 将时域点写入X1 memcpy(X1, TD, sizeof(complex<double>) * count); // 采用蝶形算法进行快速付立叶变换 for(k = 0; k < r; k++) { for(j = 0; j < 1 << k; j++) { bfsize = 1 << (r-k); for(i = 0; i < bfsize / 2; i++) { p = j * bfsize; X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2]; X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2]) * W[i * (1<<k)]; } } X = X1; X1 = X2; X2 = X; } // 重新排序 for(j = 0; j < count; j++) { p = 0; for(i = 0; i < r; i++) { if (j&(1<<i)) { p+=1<<(r-i-1); } } FD[j]=X1[p]; } // 释放内存 delete W; delete X1; delete X2; } /************************************************************************* * * 函数名称: * IFFT() * * 参数: * complex<double> * FD - 指向频域值的指针 * complex<double> * TD - 指向时域值的指针 * r -2的幂数 * * 返回值: * 无。 * * 说明: * 该函数用来实现快速付立叶反变换。 * ************************************************************************/ VOID WINAPI IFFT(complex<double> * FD, complex<double> * TD, int r) { // 付立叶变换点数 LONG count; // 循环变量 int i; complex<double> *X; // 计算付立叶变换点数 count = 1 << r; // 分配运算所需存储器 X = new complex<double>[count]; // 将频域点写入X memcpy(X, FD, sizeof(complex<double>) * count); // 求共轭 for(i = 0; i < count; i++) { X[i] = complex<double> (X[i].real(), -X[i].imag()); } // 调用快速付立叶变换 FFT(X, TD, r); // 求时域点的共轭 for(i = 0; i < count; i++) { TD[i] = complex<double> (TD[i].real() / count, -TD[i].imag() / count); } // 释放内存 delete X; } /************************************************************************* * * 函数名称: * Fourier() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行付立叶变换。 * ************************************************************************/ BOOL WINAPI Fourier(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; // 中间变量 double dTemp; // 循环变量 LONG i; LONG j; // 进行付立叶变换的宽度和高度(2的整数次方) LONG w; LONG h; int wp; int hp; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 赋初值 w = 1; h = 1; wp = 0; hp = 0; // 计算进行付立叶变换的宽度和高度(2的整数次方) while(w * 2 <= lWidth) { w *= 2; wp++; } while(h * 2 <= lHeight) { h *= 2; hp++; } // 分配内存 complex<double> *TD = new complex<double>[w * h]; complex<double> *FD = new complex<double>[w * h]; // 行 for(i = 0; i < h; i++) { // 列 for(j = 0; j < w; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 给时域赋值 TD[j + w * i] = complex<double>(*(lpSrc), 0); } } for(i = 0; i < h; i++) { // 对y方向进行快速付立叶变换 FFT(&TD[w * i], &FD[w * i], wp); } // 保存变换结果 for(i = 0; i < h; i++) { for(j = 0; j < w; j++) { TD[i + h * j] = FD[j + w * i]; } } for(i = 0; i < w; i++) { // 对x方向进行快速付立叶变换 FFT(&TD[i * h], &FD[i * h], hp); } // 行 for(i = 0; i < h; i++) { // 列 for(j = 0; j < w; j++) { // 计算频谱 dTemp = sqrt(FD[j * h + i].real() * FD[j * h + i].real() + FD[j * h + i].imag() * FD[j * h + i].imag()) / 100; // 判断是否超过255 if (dTemp > 255) { // 对于超过的,直接设置为255 dTemp = 255; } // 指向DIB第(i<h/2 ? i+h/2 : i-h/2)行,第(j<w/2 ? j+w/2 : j-w/2)个象素的指针 // 此处不直接取i和j,是为了将变换后的原点移到中心 //lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - (i<h/2 ? i+h/2 : i-h/2)) + (j<w/2 ? j+w/2 : j-w/2); // 更新源图像 * (lpSrc) = (BYTE)(dTemp); } } // 删除临时变量 delete TD; delete FD; // 返回 return TRUE; } /************************************************************************* * * 函数名称: * DCT() * * 参数: * double * f - 指向时域值的指针 * double * F - 指向频域值的指针 * r -2的幂数 * * 返回值: * 无。 * * 说明: * 该函数用来实现快速离散余弦变换。该函数利用2N点的快速付立叶变换 * 来实现离散余弦变换。 * ************************************************************************/ VOID WINAPI DCT(double *f, double *F, int r) { // 离散余弦变换点数 LONG count; // 循环变量 int i; // 中间变量 double dTemp; complex<double> *X; // 计算离散余弦变换点数 count = 1<<r; // 分配内存 X = new complex<double>[count*2]; // 赋初值为0 memset(X, 0, sizeof(complex<double>) * count * 2); // 将时域点写入数组X for(i=0;i<count;i++) { X[i] = complex<double> (f[i], 0); } // 调用快速付立叶变换 FFT(X,X,r+1); // 调整系数 dTemp = 1/sqrt(count); // 求F[0] F[0] = X[0].real() * dTemp; dTemp *= sqrt(2); // 求F[u] for(i = 1; i < count; i++) { F[i]=(X[i].real() * cos(i*PI/(count*2)) + X[i].imag() * sin(i*PI/(count*2))) * dTemp; } // 释放内存 delete X; } /************************************************************************* * * 函数名称: * IDCT() * * 参数: * double * F - 指向频域值的指针 * double * f - 指向时域值的指针 * r -2的幂数 * * 返回值: * 无。 * * 说明: * 该函数用来实现快速离散余弦反变换。该函数也利用2N点的快速付立叶变换 * 来实现离散余弦反变换。 * ************************************************************************/ VOID WINAPI IDCT(double *F, double *f, int r) { // 离散余弦反变换点数 LONG count; // 循环变量 int i; // 中间变量 double dTemp, d0; complex<double> *X; // 计算离散余弦变换点数 count = 1<<r; // 分配内存 X = new complex<double>[count*2]; // 赋初值为0 memset(X, 0, sizeof(complex<double>) * count * 2); // 将频域变换后点写入数组X for(i=0;i<count;i++) { X[i] = complex<double> (F[i] * cos(i*PI/(count*2)), F[i] * sin(i*PI/(count*2))); } // 调用快速付立叶反变换 IFFT(X,X,r+1); // 调整系数 dTemp = sqrt(2.0/count); d0 = (sqrt(1.0/count) - dTemp) * F[0]; // 计算f(x) for(i = 0; i < count; i++) { f[i] = d0 + X[i].real()* dTemp * 2 * count; } // 释放内存 delete X; } /************************************************************************* * * 函数名称: * DIBDct() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行离散余弦变换。 * ************************************************************************/ BOOL WINAPI DIBDct(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 进行付立叶变换的宽度和高度(2的整数次方) LONG w; LONG h; // 中间变量 double dTemp; int wp; int hp; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 赋初值 w = 1; h = 1; wp = 0; hp = 0; // 计算进行离散余弦变换的宽度和高度(2的整数次方) while(w * 2 <= lWidth) { w *= 2; wp++; } while(h * 2 <= lHeight) { h *= 2; hp++; } // 分配内存 double *f = new double[w * h]; double *F = new double[w * h]; // 行 for(i = 0; i < h; i++) { // 列 for(j = 0; j < w; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 给时域赋值 f[j + i * w] = *(lpSrc); } } for(i = 0; i < h; i++) { // 对y方向进行离散余弦变换 DCT(&f[w * i], &F[w * i], wp); } // 保存计算结果 for(i = 0; i < h; i++) { for(j = 0; j < w; j++) { f[j * h + i] = F[j + w * i]; } } for(j = 0; j < w; j++) { // 对x方向进行离散余弦变换 DCT(&f[j * h], &F[j * h], hp); } // 行 for(i = 0; i < h; i++) { // 列 for(j = 0; j < w; j++) { // 计算频谱 dTemp = fabs(F[j*h+i]); // 判断是否超过255 if (dTemp > 255) { // 对于超过的,直接设置为255 dTemp = 255; } // 指向DIB第y行,第x个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 更新源图像 * (lpSrc) = (BYTE)(dTemp); } } // 释放内存 delete f; delete F; // 返回 return TRUE; } /************************************************************************* * * 函数名称: * WALSH() * * 参数: * double * f - 指向时域值的指针 * double * F - 指向频域值的指针 * r -2的幂数 * * 返回值: * 无。 * * 说明: * 该函数用来实现快速沃尔什-哈达玛变换。 * ************************************************************************/ VOID WINAPI WALSH(double *f, double *F, int r) { // 沃尔什-哈达玛变换点数 LONG count; // 循环变量 int i,j,k; // 中间变量 int bfsize,p; double *X1,*X2,*X; // 计算快速沃尔什变换点数 count = 1 << r; // 分配运算所需的数组 X1 = new double[count]; X2 = new double[count]; // 将时域点写入数组X1 memcpy(X1, f, sizeof(double) * count); // 蝶形运算 for(k = 0; k < r; k++) { for(j = 0; j < 1<<k; j++) { bfsize = 1 << (r-k); for(i = 0; i < bfsize / 2; i++) { p = j * bfsize; X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2]; X2[i + p + bfsize / 2] = X1[i + p] - X1[i + p + bfsize / 2]; } } // 互换X1和X2 X = X1; X1 = X2; X2 = X; } // 调整系数 for(j = 0; j < count; j++) { p = 0; for(i = 0; i < r; i++) { if (j & (1<<i)) { p += 1 << (r-i-1); } } F[j] = X1[p] / count; } // 释放内存 delete X1; delete X2; } /************************************************************************* * * 函数名称: * IWALSH() * * 参数: * double * F - 指向频域值的指针 * double * f - 指向时域值的指针 * r -2的幂数 * * 返回值: * 无。 * * 说明: * 该函数用来实现快速沃尔什-哈达玛反变换。 * ************************************************************************/ VOID WINAPI IWALSH(double *F, double *f, int r) { // 变换点数 LONG count; // 循环变量 int i; // 计算变换点数 count = 1 << r; // 调用快速沃尔什-哈达玛变换进行反变换 WALSH(F, f, r); // 调整系数 for(i = 0; i < count; i++) { f[i] *= count; } } /************************************************************************* * * 函数名称: * DIBWalsh() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行沃尔什-哈达玛变换。函数首先对图像每列进行一维 * 沃尔什-哈达玛变换,然后对变换结果的每行进行一维沃尔什-哈达玛变换。 * ************************************************************************/ BOOL WINAPI DIBWalsh(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 进行付立叶变换的宽度和高度(2的整数次方) LONG w; LONG h; // 中间变量 double dTemp; int wp; int hp; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 赋初值 w = 1; h = 1; wp = 0; hp = 0; // 计算进行离散余弦变换的宽度和高度(2的整数次方) while(w * 2 <= lWidth) { w *= 2; wp++; } while(h * 2 <= lHeight) { h *= 2; hp++; } // 分配内存 double *f = new double[w * h]; double *F = new double[w * h]; // 行 for(i = 0; i < h; i++) { // 列 for(j = 0; j < w; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 给时域赋值 f[j + i * w] = *(lpSrc); } } for(i = 0; i < h; i++) { // 对y方向进行沃尔什-哈达玛变换 WALSH(f + w * i, F + w * i, wp); } // 保存计算结果 for(i = 0; i < h; i++) { for(j = 0; j < w; j++) { f[j * h + i] = F[j + w * i]; } } for(j = 0; j < w; j++) { // 对x方向进行沃尔什-哈达玛变换 WALSH(f + j * h, F + j * h, hp); } // 行 for(i = 0; i < h; i++) { // 列 for(j = 0; j < w; j++) { // 计算频谱 dTemp = fabs(F[j * h + i] * 1000); // 判断是否超过255 if (dTemp > 255) { // 对于超过的,直接设置为255 dTemp = 255; } // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j; // 更新源图像 * (lpSrc) = (BYTE)(dTemp); } } //释放内存 delete f; delete F; // 返回 return TRUE; } /************************************************************************* * * 函数名称: * DIBWalsh1() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用来对图像进行沃尔什-哈达玛变换。于上面不同的是,此处是将二维 * 矩阵转换成一个列向量,然后对该列向量进行一次一维沃尔什-哈达玛变换。 * ************************************************************************/ BOOL WINAPI DIBWalsh1(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 进行付立叶变换的宽度和高度(2的整数次方) LONG w; LONG h; // 中间变量 double dTemp; int wp; int hp; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 赋初值 w = 1; h = 1; wp = 0; hp = 0; // 计算进行离散余弦变换的宽度和高度(2的整数次方) while(w * 2 <= lWidth) { w *= 2; wp++; } while(h * 2 <= lHeight) { h *= 2; hp++; } // 分配内存 double *f = new double[w * h]; double *F = new double[w * h]; // 列 for(i = 0; i < w; i++) { // 行 for(j = 0; j < h; j++) { // 指向DIB第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - j) + i; // 给时域赋值 f[j + i * w] = *(lpSrc); } } // 调用快速沃尔什-哈达玛变换 WALSH(f, F, wp + hp); // 列 for(i = 0; i < w; i++) { // 行 for(j = 0; j < h; j++) { // 计算频谱 dTemp = fabs(F[i * w + j] * 1000); // 判断是否超过255 if (dTemp > 255) { // 对于超过的,直接设置为255 dTemp = 255; } // 指向DIB第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - j) + i; // 更新源图像 * (lpSrc) = (BYTE)(dTemp); } } //释放内存 delete f; delete F; // 返回 return TRUE; } /************************************************************************* * * 函数名称: * ThresholdDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行阈值分割运算。 * ************************************************************************/ BOOL WINAPI ThresholdDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; //像素值 unsigned char pixel; //直方图数组 long lHistogram[256]; //阈值,最大灰度值与最小灰度值,两个区域的平均灰度值 unsigned char iThreshold,iNewThreshold,iMaxGrayValue,iMinGrayValue,iMean1GrayValue,iMean2GrayValue; //用于计算区域灰度平均值的中间变量 long lP1,lP2,lS1,lS2; //迭代次数 int iIterationTimes; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for (i = 0; i < 256;i++) { lHistogram[i]=0; } //获得直方图 iMaxGrayValue = 0; iMinGrayValue = 255; for (i = 0;i < lWidth ;i++) { for(j = 0;j < lHeight ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; lHistogram[pixel]++; //修改最大,最小灰度值 if(iMinGrayValue > pixel) { iMinGrayValue = pixel; } if(iMaxGrayValue < pixel) { iMaxGrayValue = pixel; } } } //迭代求最佳阈值 iNewThreshold = (iMinGrayValue + iMaxGrayValue)/2; iThreshold = 0; for(iIterationTimes = 0; iThreshold != iNewThreshold && iIterationTimes < 100;iIterationTimes ++) { iThreshold = iNewThreshold; lP1 =0; lP2 =0; lS1 = 0; lS2 = 0; //求两个区域的灰度平均值 for (i = iMinGrayValue;i < iThreshold;i++) { lP1 += lHistogram[i]*i; lS1 += lHistogram[i]; } iMean1GrayValue = (unsigned char)(lP1 / lS1); for (i = iThreshold+1;i < iMaxGrayValue;i++) { lP2 += lHistogram[i]*i; lS2 += lHistogram[i]; } iMean2GrayValue = (unsigned char)(lP2 / lS2); iNewThreshold = (iMean1GrayValue + iMean2GrayValue)/2; } //根据阈值将图像二值化 for (i = 0;i < lWidth ;i++) { for(j = 0;j < lHeight ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; if(pixel <= iThreshold) { *lpDst = (unsigned char)0; } else { *lpDst = (unsigned char)255; } } } // 复制图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * AddMinusDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LPSTR lpDIBBitsBK - 指向背景DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * bool bAddMinus - 为true时执行加运算,否则执行减运算。 * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行加减运算。 * * 要求目标图像为255个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI AddMinusDIB(LPSTR lpDIBBits, LPSTR lpDIBBitsBK, LONG lWidth, LONG lHeight ,bool bAddMinus) { // 指向源图像的指针 LPSTR lpSrc,lpSrcBK; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; //像素值 unsigned char pixel,pixelBK; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for (j = 0;j < lHeight ;j++) { for(i = 0;i < lWidth ;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; lpSrcBK = (char *)lpDIBBitsBK + lLineBytes * j + i; // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; pixelBK = (unsigned char)*lpSrcBK; if(bAddMinus) *lpDst = pixel + pixelBK > 255 ? 255 : pixel + pixelBK; else *lpDst = pixel - pixelBK < 0 ? 0 : pixel - pixelBK; } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * HprojectDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行水平投影运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI HprojectDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; //图像中每行内的黑点个数 long lBlackNumber; //像素值 unsigned char pixel; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for (j = 0;j < lHeight ;j++) { lBlackNumber = 0; for(i = 0;i < lWidth ;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; if (pixel != 255 && pixel != 0) { return false; } if(pixel == 0) { lBlackNumber++; } } for(i = 0;i < lBlackNumber ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + (lWidth - i); *lpDst = (unsigned char)0; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } BOOL WINAPI HDifferProjDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber); lTotalNumber = new long[1000];//平滑模板 lSmooth1 = new long[1000]; lSmooth2 = new long[1000]; lBlackNumber = new long[1000]; long lMax; float fAlpha; fAlpha = 0.2; //像素值 unsigned char pixel; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for(i = 0; i < 1000; i++) { lTotalNumber[i] = 0; lBlackNumber[i] = 0; lSmooth1[i] = 0; lSmooth2[i] = 0; } for (j = 0;j < lHeight ;j++) { for(i = 0;i < lWidth ;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; lTotalNumber[j] += pixel; } } // 求最大值 lMax = 0; for(i = 0; i < 1000;i++) { if(lTotalNumber[i] >= lMax) { lMax = lTotalNumber[i]; } } // 平滑 lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax)); lSmooth2[0] = lSmooth1[0]; lBlackNumber[0] = lSmooth2[0]; // 一次平滑 for (j = 1;j < lHeight ;j++) { lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax)); lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]); // lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); } // 二次平滑 for (j = 1;j < lHeight ;j++) { lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); } // 赋值 for (j = 0;j < lHeight ;j++) { for(i = 0;i < lBlackNumber[j] ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + (lWidth - i); *lpDst = (unsigned char)0; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); delete []lTotalNumber; delete []lBlackNumber; delete []lSmooth1; delete []lSmooth2; // 返回 return TRUE; } BOOL WINAPI HDifferProjDIB2(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; int iExtrem; long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber); long (*lDiffer); int (*iMaxOrMin); lTotalNumber = new long[1000];//平滑模板 lSmooth1 = new long[1000]; lSmooth2 = new long[1000]; lBlackNumber = new long[1000]; lDiffer = new long[1000]; iMaxOrMin = new int[1000]; long lMax; float fAlpha; fAlpha = 0.2; //像素值 unsigned char pixel; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for(i = 0; i < 1000; i++) { lTotalNumber[i] = 0; lBlackNumber[i] = 0; lSmooth1[i] = 0; lSmooth2[i] = 0; lDiffer[i] = 0; iMaxOrMin[i] = 0; } for (j = 0;j < lHeight ;j++) { for(i = 0;i < lWidth ;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; lTotalNumber[j] += pixel; } } // 求最大值 lMax = 0; for(i=0;i<1000;i++) { if(lTotalNumber[i] >= lMax) { lMax = lTotalNumber[i]; } } // 平滑 lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax)); lSmooth2[0] = lSmooth1[0]; lBlackNumber[0] = lSmooth2[0]; // 一次平滑 for (j = 1;j < lHeight ;j++) { // lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax)); lSmooth1[j] = lTotalNumber[j]; lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]); // lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); } // 二次平滑 for (j = 1;j < lHeight ;j++) { lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); lDiffer[j - 1] = lBlackNumber[j] - lBlackNumber[j - 1]; } // 判断极值 iExtrem = 1; for (j = 1;j < lHeight ;j++) { // 极大值 // if((lBlackNumber[j-1]>lBlackNumber[j])&&(lBlackNumber[j+1]>=lBlackNumber[j])) if((lDiffer[j - 1] > 0)&&(lDiffer[j] <= 0)) { iMaxOrMin[iExtrem] = j; iExtrem++; } // 极小值 // else if((lBlackNumber[j-1]<=lBlackNumber[j])&&(lBlackNumber[j+1]<lBlackNumber[j])) else if((lDiffer[j - 1] < 0)&&(lDiffer[j] >= 0)) { iMaxOrMin[iExtrem] = -1 * j; iExtrem++; } } // 提取有效波谷 i=iExtrem-1; j=iExtrem-2; int a1,a2,a3,a4,a5,a6,b1,b2,b3; do { int q1 =0; a1 = iMaxOrMin[i]; a2 = iMaxOrMin[j]; a3 = iMaxOrMin[j-1]; if(i<iExtrem-2) { a4=iMaxOrMin[i+1]; a5=iMaxOrMin[i+2]; } b1 = lBlackNumber[abs(iMaxOrMin[i])]; b2 = lBlackNumber[abs(iMaxOrMin[j])]; b3 = lBlackNumber[abs(iMaxOrMin[j-1])]; int q3=0; // 前为极大值,后为极大值 if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] ) { iMaxOrMin[j] = 0; //i = j + 1; j = j - 1; } else { iMaxOrMin[i] = 0; i = j; j = i - 1; } } // 前为极小值,后为极小值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j])]) { iMaxOrMin[j] = 0; //i = j + 1;//j=j+1 j = j - 1;// } else { iMaxOrMin[i] = 0; i = j; j = i - 1; } } // 前为极大值,后为极小值 else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 50))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j - 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j - 1] = 0; j = j - 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j - 1; j = i - 1; } } // 前为极小值,后为极大值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 50))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j - 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j - 1] = 0; j = j - 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j - 1; j = i - 1; } } else { i = j; j = j - 1; } int q2=0; }while( j > 1); /* i=1; j=2; int a1,a2,a3,a4,a5,a6,b1,b2,b3; do { int q1 =0; a1 = iMaxOrMin[i]; a2 = iMaxOrMin[j]; a3 = iMaxOrMin[j+1]; if(i>1) { a4=iMaxOrMin[i-1]; a5=iMaxOrMin[i-2]; } b1 = lBlackNumber[abs(iMaxOrMin[i])]; b2 = lBlackNumber[abs(iMaxOrMin[j])]; b3 = lBlackNumber[abs(iMaxOrMin[j+1])]; int q3=0; // 前为极大值,后为极大值 if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] ) { iMaxOrMin[j] = 0; //i = j + 1; j = j + 1; } else { iMaxOrMin[i] = 0; i = j; j = i + 1; } } // 前为极小值,后为极小值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j])]) { iMaxOrMin[j] = 0; //i = j + 1;//j=j+1 j = j + 1;// } else { iMaxOrMin[i] = 0; i = j; j = i + 1; } } // 前为极大值,后为极小值 else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 30))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j + 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j + 1] = 0; j = j + 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j + 1; j = i + 1; } } // 前为极小值,后为极大值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 30))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j + 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j + 1] = 0; j = j + 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j + 1; j = i + 1; } } else { i = j; j = j + 1; } int q2=0; }while( j < iExtrem); */ /* do { int q=0; // 前为极大值,后为极大值 if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] ) { iMaxOrMin[j] = 0; i = j + 1; j = i + 1; } else { iMaxOrMin[i] = 0; i = j; j = i + 1; } } // 前为极小值,后为极小值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j])]) { iMaxOrMin[j] = 0; i = j + 1;//j=j+1 j = i + 1;// } else { iMaxOrMin[i] = 0; i = j; j = i + 1; } } // 前为极大值,后为极小值 else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 20))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j + 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j + 1] = 0; j = j + 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j + 1; j = i + 1; } } // 前为极小值,后为极大值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 20))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j + 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j + 1] = 0; j = j + 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j + 1; j = i + 1; } } else { i = j; j = j + 1; } }while( j < iExtrem); */ // lSmooth1[j] = (long)( lWidth * lBlackNumber[j] / ( 2 * lMax)); for (j = 1;j < iExtrem ;j++) { a1=iMaxOrMin[j]; a2=lBlackNumber[abs(iMaxOrMin[j])]; a3=0; } // 赋值 for (j = 1;j < iExtrem ;j++) { int q5=0; a1=iMaxOrMin[j]; a2=abs(iMaxOrMin[j]); a3=lBlackNumber[abs(iMaxOrMin[j])]; a4=0; if(iMaxOrMin[j] < 0)//||(iMaxOrMin[j] == 1)) // if(iMaxOrMin[j] == 1) { for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxOrMin[j])] / ( 2 * lMax)) ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxOrMin[j]) + i; *lpDst = (unsigned char)0; } int q8=0; } else if(iMaxOrMin[j] > 0) { for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxOrMin[j])] / ( 2 * lMax)) ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 if((int)fmod(i,5)==0) { lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxOrMin[j]) + i; *lpDst = (unsigned char)0; } } int q9=0; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); delete []lTotalNumber; delete []lBlackNumber; delete []lSmooth1; delete []lSmooth2; delete []lDiffer; delete []iMaxOrMin; // 返回 return TRUE; } BOOL WINAPI HDifferProjDIB3(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; int iExtrem,iExtrem2,iBottom1,iBottom2; long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber); long (*lDiffer); int (*iMaxOrMin),(*iMaxAndMin); lTotalNumber = new long[1000];//平滑模板 lSmooth1 = new long[1000]; lSmooth2 = new long[1000]; lBlackNumber = new long[1000]; lDiffer = new long[1000]; iMaxOrMin = new int[1000]; iMaxAndMin = new int[1000]; long lMax; float fAlpha; fAlpha = 0.2; //像素值 unsigned char pixel; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for(i = 0; i < 1000; i++) { lTotalNumber[i] = 0; lBlackNumber[i] = 0; lSmooth1[i] = 0; lSmooth2[i] = 0; lDiffer[i] = 0; iMaxOrMin[i] = 0; iMaxAndMin[i] = 0; } for (j = 0;j < lHeight ;j++) { for(i = 0;i < lWidth ;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; lTotalNumber[j] += pixel; } } // 求最大值 lMax = 0; for(i=0;i<1000;i++) { if(lTotalNumber[i] >= lMax) { lMax = lTotalNumber[i]; } } // 平滑 lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax)); lSmooth2[0] = lSmooth1[0]; lBlackNumber[0] = lSmooth2[0]; // 一次平滑 for (j = 1;j < lHeight ;j++) { // lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax)); lSmooth1[j] = lTotalNumber[j]; lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]); // lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); } // 二次平滑 for (j = 1;j < lHeight ;j++) { lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); lDiffer[j - 1] = lBlackNumber[j] - lBlackNumber[j - 1]; } // 判断极值 iExtrem = 1; for (j = 1;j < lHeight ;j++) { // 极大值 // if((lBlackNumber[j-1]>lBlackNumber[j])&&(lBlackNumber[j+1]>=lBlackNumber[j])) if((lDiffer[j - 1] > 0)&&(lDiffer[j] <= 0)) { iMaxOrMin[iExtrem] = j; iExtrem++; } // 极小值 // else if((lBlackNumber[j-1]<=lBlackNumber[j])&&(lBlackNumber[j+1]<lBlackNumber[j])) else if((lDiffer[j - 1] < 0)&&(lDiffer[j] >= 0)) { iMaxOrMin[iExtrem] = -1 * j; iExtrem++; } } // 提取有效波谷 i=iExtrem-1; j=iExtrem-2; int a1,a2,a3,a4,a5,a6,b1,b2,b3; do { int q1 =0; a1 = iMaxOrMin[i]; a2 = iMaxOrMin[j]; a3 = iMaxOrMin[j-1]; if(i<iExtrem-2) { a4=iMaxOrMin[i+1]; a5=iMaxOrMin[i+2]; } b1 = lBlackNumber[abs(iMaxOrMin[i])]; b2 = lBlackNumber[abs(iMaxOrMin[j])]; b3 = lBlackNumber[abs(iMaxOrMin[j-1])]; // 前为极大值,后为极大值 if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] ) { iMaxOrMin[j] = 0; //i = j + 1; j = j - 1; } else { iMaxOrMin[i] = 0; i = j; j = i - 1; } } // 前为极小值,后为极小值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j])]) { iMaxOrMin[j] = 0; //i = j + 1;//j=j+1 j = j - 1;// } else { iMaxOrMin[i] = 0; i = j; j = i - 1; } } // 前为极大值,后为极小值 else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j - 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j - 1] = 0; j = j - 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j - 1; j = i - 1; } } // 前为极小值,后为极大值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j - 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j - 1] = 0; j = j - 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j - 1; j = i - 1; } } else { i = j; j = j - 1; } }while( j > 1); // 对波谷进一步提取 iExtrem2=1; for (j = 1;j < iExtrem ;j++) { if((iMaxOrMin[j] != 0)&&(-iMaxOrMin[j]<3000)) { iMaxAndMin[iExtrem2] = iMaxOrMin[j]; iExtrem2++; } } int q2=0; for(j=1;j < iExtrem2;j++) { if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j + 1] > 0)&&(iMaxAndMin[j + 2] < 0)) { // 车牌区域差影区应满足的条件 if( (abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) >15) &&(abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) <80) &&(abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j+1])]) >60) &&(abs(lBlackNumber[abs(iMaxAndMin[j+1])] - lBlackNumber[abs(iMaxAndMin[j+2])]) >60) ) {;} else { iMaxAndMin[j] = 0; } } } for(j=1;j < iExtrem2;j++) { if((iMaxAndMin[j] > 0)&&(iMaxAndMin[j + 1] < 0)&&(iMaxAndMin[j + 2] > 0)) { // 车牌区域差影区应满足的条件 if( (abs(iMaxAndMin[j] + iMaxAndMin[j + 1]) <10) &&(abs(iMaxAndMin[j + 1] + iMaxAndMin[j + 2]) <10) ) // &&( (abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j - 1])]) < 10) // ||(abs(lBlackNumber[abs(iMaxAndMin[j - 1])] - lBlackNumber[abs(iMaxAndMin[j - 2])]) <10))) { iMaxAndMin[j + 1] = 0; } else {;} } } /* for(j=iExtrem2;j > 1;j--) { if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j - 1] > 0)) // ||(iMaxAndMin[j] > 0)&&(iMaxAndMin[j - 1] < 0)) { // 车牌区域差影区应满足的条件 if( ( abs ( lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j-1])] ) >100 )&& ( abs ( iMaxAndMin[j] + iMaxAndMin[j - 1] ) >10 ) ) {;} else { iMaxAndMin[j] = 0; iMaxAndMin[j-1] = 0; } } } */ iBottom1=0; iBottom2=0; /* for(j=iExtrem2;j > 1;) { if((iMaxAndMin[j] < 0)&&(iBottom2=0)) { iBottom1 = iMaxAndMin[j]; iBottom2=1; j--; } else if((iMaxAndMin[j] < 0)&&(iBottom1 != 0)) { iBottom2 = iMaxAndMin[j]; if( (abs(iBottom1 - iBottom2) >20) &&(abs(iBottom1 - iBottom2) <60)) {;} else { iMaxAndMin[j] = 0; } iBottom2=0; j--; } else { j--; } } */ int q3=0; // 赋值 for (j = 1;j < iExtrem2 ;j++) { int q5=0; a1=iMaxAndMin[j]; a2=abs(iMaxAndMin[j]); a3=lBlackNumber[abs(iMaxAndMin[j])]; a4=0; if(iMaxAndMin[j] < 0)//||(iMaxOrMin[j] == 1)) // if(iMaxOrMin[j] == 1) { for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i; *lpDst = (unsigned char)0; } int q8=0; } else if(iMaxAndMin[j] > 0) { for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 if((int)fmod(i,5)==0) { lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i; *lpDst = (unsigned char)0; } } int q9=0; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); delete []lTotalNumber; delete []lBlackNumber; delete []lSmooth1; delete []lSmooth2; delete []lDiffer; delete []iMaxOrMin; delete []iMaxAndMin; // 返回 return TRUE; } int* WINAPI HDifferProjDIB4(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; int* pPlateLine; int iPlateLine[40]; //循环变量 long i; long j; int iExtrem,iExtrem2,iExtrem3,iBottom1,iBottom2; long (*lTotalNumber),(*lSmooth1),(*lSmooth2),(*lBlackNumber); long (*lDiffer); int (*iMaxOrMin),(*iMaxAndMin); lTotalNumber = new long[1000];//平滑模板 lSmooth1 = new long[1000]; lSmooth2 = new long[1000]; lBlackNumber = new long[1000]; lDiffer = new long[1000]; iMaxOrMin = new int[1000]; iMaxAndMin = new int[1000]; long lMax; float fAlpha; fAlpha = 0.2; //像素值 unsigned char pixel; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for(i = 0; i < 1000; i++) { lTotalNumber[i] = 0; lBlackNumber[i] = 0; lSmooth1[i] = 0; lSmooth2[i] = 0; lDiffer[i] = 0; iMaxOrMin[i] = 0; iMaxAndMin[i] = 0; } for (j = 0;j < lHeight ;j++) { for(i = 0;i < lWidth ;i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; lTotalNumber[j] += pixel; } } // 求最大值 lMax = 0; for(i=0;i<1000;i++) { if(lTotalNumber[i] >= lMax) { lMax = lTotalNumber[i]; } } // 平滑 lSmooth1[0] = (long)( lWidth * lTotalNumber[0] / ( 2 * lMax)); lSmooth2[0] = lSmooth1[0]; lBlackNumber[0] = lSmooth2[0]; // 一次平滑 for (j = 1;j < lHeight ;j++) { // lSmooth1[j] = (long)( lWidth * lTotalNumber[j] / ( 2 * lMax)); lSmooth1[j] = lTotalNumber[j]; lSmooth2[j] = (long)( (float)fAlpha * lSmooth1[j] + (1.0 - fAlpha) * (float)lSmooth1[j-1]); // lBlackNumber[j] = (long)( (float)fAlpha * lSmooth[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); } // 二次平滑 for (j = 1;j < lHeight ;j++) { lBlackNumber[j] = (long)( (float)fAlpha * lSmooth2[j] + (1.0 - fAlpha) * (float)lBlackNumber[j-1]); lDiffer[j - 1] = lBlackNumber[j] - lBlackNumber[j - 1]; } // 判断极值 iExtrem = 1; for (j = 1;j < lHeight ;j++) { // 极大值 // if((lBlackNumber[j-1]>lBlackNumber[j])&&(lBlackNumber[j+1]>=lBlackNumber[j])) if((lDiffer[j - 1] > 0)&&(lDiffer[j] <= 0)) { iMaxOrMin[iExtrem] = j; iExtrem++; } // 极小值 // else if((lBlackNumber[j-1]<=lBlackNumber[j])&&(lBlackNumber[j+1]<lBlackNumber[j])) else if((lDiffer[j - 1] < 0)&&(lDiffer[j] >= 0)) { iMaxOrMin[iExtrem] = -1 * j; iExtrem++; } } // 提取有效波谷 i=iExtrem-1; j=iExtrem-2; int a1,a2,a3,a4,a5,a6,b1,b2,b3; do { int q1 =0; a1 = iMaxOrMin[i]; a2 = iMaxOrMin[j]; a3 = iMaxOrMin[j-1]; if(i<iExtrem-2) { a4=iMaxOrMin[i+1]; a5=iMaxOrMin[i+2]; } b1 = lBlackNumber[abs(iMaxOrMin[i])]; b2 = lBlackNumber[abs(iMaxOrMin[j])]; b3 = lBlackNumber[abs(iMaxOrMin[j-1])]; // 前为极大值,后为极大值 if((iMaxOrMin[i] > 0)&&(iMaxOrMin[j] > 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j])] ) { iMaxOrMin[j] = 0; //i = j + 1; j = j - 1; } else { iMaxOrMin[i] = 0; i = j; j = i - 1; } } // 前为极小值,后为极小值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] < 0)) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j])]) { iMaxOrMin[j] = 0; //i = j + 1;//j=j+1 j = j - 1;// } else { iMaxOrMin[i] = 0; i = j; j = i - 1; } } // 前为极大值,后为极小值 else if( (iMaxOrMin[i] > 0) && (iMaxOrMin[j] < 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] >= lBlackNumber[abs(iMaxOrMin[j - 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j - 1] = 0; j = j - 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j - 1; j = i - 1; } } // 前为极小值,后为极大值 else if((iMaxOrMin[i] < 0)&&(iMaxOrMin[j] > 0) && (labs(lBlackNumber[abs(iMaxOrMin[i])] - lBlackNumber[abs(iMaxOrMin[j])] ) <= 60))//(long)lMax/16 )) { if(lBlackNumber[abs(iMaxOrMin[i])] <= lBlackNumber[abs(iMaxOrMin[j - 1])] ) { iMaxOrMin[j] = 0; iMaxOrMin[j - 1] = 0; j = j - 2; } else { iMaxOrMin[i] = 0; iMaxOrMin[j] = 0; i = j - 1; j = i - 1; } } else { i = j; j = j - 1; } }while( j > 1); // 对波谷进一步提取 iExtrem2=1; for (j = 1;j < iExtrem ;j++) { if((iMaxOrMin[j] != 0)&&(-iMaxOrMin[j]<3000)) { iMaxAndMin[iExtrem2] = iMaxOrMin[j]; iExtrem2++; } } for(j=1;j < iExtrem2;j++) { if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j + 1] > 0)&&(iMaxAndMin[j + 2] < 0)) { // 车牌区域差影区应满足的条件 if( (abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) >15) &&(abs(iMaxAndMin[j] - iMaxAndMin[j + 2]) <80) &&(abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j+1])]) >60) &&(abs(lBlackNumber[abs(iMaxAndMin[j+1])] - lBlackNumber[abs(iMaxAndMin[j+2])]) >60) ) {;} else { iMaxAndMin[j] = 0; } } } for(j=1;j < iExtrem2;j++) { if((iMaxAndMin[j] > 0)&&(iMaxAndMin[j + 1] < 0)&&(iMaxAndMin[j + 2] > 0)) { // 车牌区域差影区应满足的条件 if( (abs(iMaxAndMin[j] + iMaxAndMin[j + 1]) <10) &&(abs(iMaxAndMin[j + 1] + iMaxAndMin[j + 2]) <10) ) // &&( (abs(lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j - 1])]) < 10) // ||(abs(lBlackNumber[abs(iMaxAndMin[j - 1])] - lBlackNumber[abs(iMaxAndMin[j - 2])]) <10))) { iMaxAndMin[j + 1] = 0; } else {;} } } iExtrem3=1; for (j = 1;j < iExtrem2-1 ;j++) { if(iMaxAndMin[j] < 0) { int q2=0; iMaxAndMin[iExtrem3] = iMaxAndMin[j]; iExtrem3++; int q3=0; } } for(j=iExtrem3-1;j > 1;j--) { // 两波谷位置之差小于20行 if( abs(iMaxAndMin[j] - iMaxAndMin[j - 1]) <20) { iMaxAndMin[j] = 0; } } /* for(j=iExtrem2;j > 1;j--) { if((iMaxAndMin[j] < 0)&&(iMaxAndMin[j - 1] > 0)) // ||(iMaxAndMin[j] > 0)&&(iMaxAndMin[j - 1] < 0)) { // 车牌区域差影区应满足的条件 if( ( abs ( lBlackNumber[abs(iMaxAndMin[j])] - lBlackNumber[abs(iMaxAndMin[j-1])] ) >100 )&& ( abs ( iMaxAndMin[j] + iMaxAndMin[j - 1] ) >10 ) ) {;} else { iMaxAndMin[j] = 0; iMaxAndMin[j-1] = 0; } } } */ iBottom1=0; iBottom2=0; /* for(j=iExtrem2;j > 1;) { if((iMaxAndMin[j] < 0)&&(iBottom2=0)) { iBottom1 = iMaxAndMin[j]; iBottom2=1; j--; } else if((iMaxAndMin[j] < 0)&&(iBottom1 != 0)) { iBottom2 = iMaxAndMin[j]; if( (abs(iBottom1 - iBottom2) >20) &&(abs(iBottom1 - iBottom2) <60)) {;} else { iMaxAndMin[j] = 0; } iBottom2=0; j--; } else { j--; } } */ // 赋值 for (j = 1;j < iExtrem3 ;j++) { // int q5=0; // a1=iMaxAndMin[j]; // a2=abs(iMaxAndMin[j]); // a3=lBlackNumber[abs(iMaxAndMin[j])]; // a4=0; if(iMaxAndMin[j] < 0)//||(iMaxOrMin[j] == 1)) // if(iMaxOrMin[j] == 1) { for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i; *lpDst = (unsigned char)0; } int q8=0; } else if(iMaxAndMin[j] > 0) { for(i = 0;i < (long)( lWidth * lBlackNumber[abs(iMaxAndMin[j])] / ( 2 * lMax)) ;i++) { // 指向目标图像倒数第j行,第i个象素的指针 if((int)fmod(i,5)==0) { lpDst = (char *)lpNewDIBBits + lLineBytes * abs(iMaxAndMin[j]) + i; *lpDst = (unsigned char)0; } } } } for(i=0;i<40;i++) { iPlateLine[i]=0; } int iLineNum=0; for (j = 1;j < iExtrem3;j++) { if(iMaxAndMin[j] < 0) { iPlateLine[iLineNum] = iMaxAndMin[j]; iLineNum++; } } pPlateLine = &iPlateLine[0]; int q9=0; // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); delete []lTotalNumber; delete []lBlackNumber; delete []lSmooth1; delete []lSmooth2; delete []lDiffer; delete []iMaxOrMin; delete []iMaxAndMin; // 返回 return pPlateLine; } /************************************************************************* * * 函数名称: * VprojectDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对两幅图像进行垂直投影运算。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI VprojectDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; //图像中每行内的黑点个数 long lBlackNumber; //像素值 unsigned char pixel; // 图像每行的字节数 LONG lLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for (i = 0;i < lWidth ;i++) { lBlackNumber = 0; for(j = 0;j < lHeight ;j++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; pixel = (unsigned char)*lpSrc; if (pixel != 255 && pixel != 0) { return false; } if(pixel == 0) { lBlackNumber++; } } for(j = 0;j < lBlackNumber ;j++) { // 指向目标图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + i; *lpDst = (unsigned char)0; } } // 复制投影图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * TemplateMatchDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LPSTR lpDIBBitsBK - 指向背景DIB图像指针 * LONG lWidth - 源图像宽度(象素数) * LONG lHeight - 源图像高度(象素数) * LONG lTemplateWidth - 模板图像宽度(象素数) * LONG lTemplateHeight - 模板图像高度(象素数) * * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对图像进行模板匹配运算。 * * 要求目标图像为255个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI TemplateMatchDIB (LPSTR lpDIBBits, LPSTR lpTemplateDIBBits, LONG lWidth, LONG lHeight, LONG lTemplateWidth,LONG lTemplateHeight) { // 指向源图像的指针 LPSTR lpSrc,lpTemplateSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //循环变量 long i; long j; long m; long n; //中间结果 double dSigmaST; double dSigmaS; double dSigmaT; //相似性测度 double R; //最大相似性测度 double MaxR; //最大相似性出现位置 long lMaxWidth; long lMaxHeight; //像素值 unsigned char pixel; unsigned char templatepixel; // 图像每行的字节数 LONG lLineBytes,lTemplateLineBytes; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); lTemplateLineBytes = WIDTHBYTES(lTemplateWidth * 8); //计算dSigmaT dSigmaT = 0; for (n = 0;n < lTemplateHeight ;n++) { for(m = 0;m < lTemplateWidth ;m++) { // 指向模板图像倒数第j行,第i个象素的指针 lpTemplateSrc = (char *)lpTemplateDIBBits + lTemplateLineBytes * n + m; templatepixel = (unsigned char)*lpTemplateSrc; dSigmaT += (double)templatepixel*templatepixel; } } //找到图像中最大相似性的出现位置 MaxR = 0.0; for (j = 0;j < lHeight - lTemplateHeight +1 ;j++) { for(i = 0;i < lWidth - lTemplateWidth + 1;i++) { dSigmaST = 0; dSigmaS = 0; for (n = 0;n < lTemplateHeight ;n++) { for(m = 0;m < lTemplateWidth ;m++) { // 指向源图像倒数第j+n行,第i+m个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * (j+n) + (i+m); // 指向模板图像倒数第n行,第m个象素的指针 lpTemplateSrc = (char *)lpTemplateDIBBits + lTemplateLineBytes * n + m; pixel = (unsigned char)*lpSrc; templatepixel = (unsigned char)*lpTemplateSrc; dSigmaS += (double)pixel*pixel; dSigmaST += (double)pixel*templatepixel; } } //计算相似性 R = dSigmaST / ( sqrt(dSigmaS)*sqrt(dSigmaT)); //与最大相似性比较 if (R > MaxR) { MaxR = R; lMaxWidth = i; lMaxHeight = j; } } } //将最大相似性出现区域部分复制到目标图像 for (n = 0;n < lTemplateHeight ;n++) { for(m = 0;m < lTemplateWidth ;m++) { lpTemplateSrc = (char *)lpTemplateDIBBits + lTemplateLineBytes * n + m; lpDst = (char *)lpNewDIBBits + lLineBytes * (n+lMaxHeight) + (m+lMaxWidth); *lpDst = *lpTemplateSrc; } } // 复制图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 返回 return TRUE; } BOOL WINAPI NUMBERSCANLINE(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { return TRUE; } BOOL WINAPI NUMBERSCANROW(LPSTR lpDIBBits,LONG lWidth, LONG lHeight) { return TRUE; } int WINAPI Distance13(LONG iWidth, LONG iHeight, int ix, int iy) { // 图像点x方向的坐标 int x = ix; // 图像点y方向的坐标 int y = iy; // 循环变量 LONG i; // 求最小距离时用到的变量 float fMin; // 该图像点对应的段的标号 int iSect; // 13段计算距离的参考坐标数组 // int iRefer[13][2]={0,0,}; // 图像点到13段的距离数组 float fDistance[14]; // 初始化距离 for(i = 0; i < 14; i++) { fDistance[i] = 100.0; } // 计算图像点到各段的距离 fDistance[1] = x * x; fDistance[2] = (x - 20) * (x - 20); fDistance[3] = (x - 39) * (x - 39); if(x < 20) { fDistance[4] = y * y; fDistance[5] = 100.0; fDistance[6] = (y - 10) * (y - 10); fDistance[7] = 100.0; fDistance[8] = (y - 20) * (y - 20); fDistance[9] = 100.0; fDistance[10] = x * x / 4.0 + y * y - x * y; fDistance[11] = 100.0; fDistance[12] = (8.0 - x / 5.0 - 2.0 * y / 5.0) * (8 - x / 5.0 - 2.0 * y / 5.0) + (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0) * (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0); fDistance[13] = 100.0; } else { fDistance[4] = 100.0 ; fDistance[5] = y * y ; fDistance[6] = 100.0 ; fDistance[7] = (y - 10) * (y - 10); fDistance[8] = 100.0 ; fDistance[9] = (y - 20) * (y - 20); fDistance[10] = 100.0; fDistance[11] = (8.0 - x / 5.0 - 2.0 * y / 5.0) * (8 - x / 5.0 - 2.0 * y / 5.0) + (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0) * (16.0 - 2.0 * x / 5.0 - 4.0 * y / 5.0); fDistance[12] = 100.0; fDistance[13] = x * x / 4.0 + y * y - x * y; } // 求最小距离 iSect = 1; fMin = fDistance[1]; for(i = 2; i < 14; i++) { if( fDistance[i] <= fMin) { fMin = fDistance[i]; iSect = i; } } return iSect; } int WINAPI Distance16(LONG iWidth, LONG iHeight, int ix, int iy) { // 图像点x方向的坐标 int x = ix; // 图像点y方向的坐标 int y = iy; // 循环变量 LONG i; // 求最小距离时用到的变量 float fMin; // 该图像点对应的段的标号 int iSect; // 图像点到13段的距离数组 float fDistance[17]; // 初始化距离 for(i = 0; i < 17; i++) { fDistance[i] = 1000.0; } // 计算图像点到各段的距离,x是垂直方向,y是水平方向 float d1,d2,d3,d4,d5,d6,d7,d8; // d1:到1、2的距离的平方 d1 = y * y; // d2:到3、4的距离的平方 d2 = (y-20) * (y-20); // d3:到5、6的距离的平方 d3 = (y-40) * (y-40); // d4:到7、8的距离的平方 d4 = x * x; // d5:到9、10的距离的平方 d5 = (x-10) * (x-10); // d6:到11、12的距离的平方 d6 = (x-20) * (x-20); // d7:到13、16的距离的平方 d7 = (y-2*x)*(y-2*x)*(0.5*y-x)*(0.5*y-x)/( ( y-2*x)*(y-2*x) + (0.5*y-x)*(0.5*y-x) ); // d8:到14、15的距离的平方 d8 = (y+2*x-40)*(y+2*x-40)*(0.5*y+x-20)*(0.5*y+x-20)/( (y+2*x-40)*(y+2*x-40) + (0.5*y+x-20)*(0.5*y+x-20) ); // 字符左下的子区域 if( (x < 10) && (y < 20) ) { fDistance[1] = d1; fDistance[3] = d2; fDistance[7] = d4; fDistance[9] = d5; fDistance[13] = d7; } // 字符右下的子区域 else if((x >= 10) && (y < 20)) { fDistance[2] = d1; fDistance[4] = d2; fDistance[9] = d5; fDistance[11] = d6; fDistance[15] = d8; } // 字符左上的子区域 else if((x < 10) && (y >= 20)) { fDistance[3] = d2; fDistance[5] = d3; fDistance[8] = d4; fDistance[10] = d5; fDistance[14] = d8; } // 字符右上的子区域 else if( (x >= 10) && (y >= 20) ) { fDistance[4] = d2; fDistance[6] = d3; fDistance[10] = d5; fDistance[12] = d6; fDistance[16] = d7; } else { AfxMessageBox("坐标错误!"); return NULL; } // 求最小距离 iSect = 1; fMin = fDistance[1]; for(i = 2; i < 17; i++) { if( fDistance[i] < fMin) { fMin = fDistance[i]; iSect = i; } } return iSect; } float* WINAPI CharExtract13Sect(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; //循环变量 long i; long lRow; long lLine; // 像素的灰度值 unsigned char pixelvalue; // 13段投影码表 float fCode13Sect[13]; // 13段投影码表指针 float* pCode13Sect; // 与图像点最近的段的标号 int iSectNum; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 初始化 iSectNum = 0; for(i = 0; i < 13; i++) { fCode13Sect[i] = 0.0; } for (lRow = 0;lRow < lWidth ;lRow++) { for(lLine = 0;lLine < lHeight ;lLine++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow; pixelvalue = (unsigned char)*lpSrc; if (pixelvalue == 0) { iSectNum = Distance13(lWidth,lHeight,lLine,lRow) - 1; fCode13Sect[iSectNum] += 1.0; } } } // 码表归一化处理 for(i = 0; i < 13; i++) { if(fCode13Sect[i] > 20.0) { fCode13Sect[i] = 20.0; } fCode13Sect[i] /= 20.0; } pCode13Sect = &fCode13Sect[0]; return pCode13Sect; } float* WINAPI CharExtract16Sect(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; //循环变量 long i,j; long lRow; long lLine; // 像素的灰度值 unsigned char pixelvalue; // 13段投影码表 float fCode16Sect[6][16]; // 13段投影码表指针 float* pCode16Sect; // 与图像点最近的段的标号 int iSectNum; int iCharNum; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 初始化 iSectNum = 0; iCharNum = 0; for(i = 0; i < 6; i++) { for(j = 0; j < 16; j++) { fCode16Sect[i][j] = 0.0; } } // 传一个有效象素提取特征 int y; for (lRow = 20;lRow < lWidth ;lRow++) { iCharNum = (int)(lRow/20); y = lRow - 20 * iCharNum; int q8=0; for(lLine = 0;lLine < lHeight ;lLine++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow; pixelvalue = (unsigned char)*lpSrc; if (pixelvalue == 0) { iSectNum = Distance16(lWidth,lHeight,y,lLine) - 1; fCode16Sect[iCharNum-1][iSectNum] += 1.0; int q9=0; } } } TRACE("\n"); // 码表归一化处理 for(i = 0; i < 6; i++) { for(j = 0; j < 16; j++) { if(fCode16Sect[i][j] > 20.0) { fCode16Sect[i][j] = 20.0; } fCode16Sect[i][j] /= 20.0; } } pCode16Sect = &fCode16Sect[0][0]; return pCode16Sect; } // 用于提取单个字符的特征 float* WINAPI CharExtract16Sect2(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; //循环变量 long i,j; long lRow; long lLine; // 像素的灰度值 unsigned char pixelvalue; // 13段投影码表 float fCode16Sect[16]; // 13段投影码表指针 float* pCode16Sect; // 与图像点最近的段的标号 int iSectNum; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); // 初始化 iSectNum = 0; for(j = 0; j < 16; j++) { fCode16Sect[j] = 0.0; } // 传一个有效象素提取特征 int y; for (lRow = 0;lRow < lWidth ;lRow++) { int q8=0; for(lLine = 0;lLine < lHeight ;lLine++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow; pixelvalue = (unsigned char)*lpSrc; if (pixelvalue == 0) { iSectNum = Distance16(lWidth,lHeight,lRow,lLine) - 1; fCode16Sect[iSectNum] += 1.0; int q9=0; } } } TRACE("\n"); // 码表归一化处理 for(j = 0; j < 16; j++) { if(fCode16Sect[j] > 20.0) { fCode16Sect[j] = 20.0; } fCode16Sect[j] /= 20.0; } pCode16Sect = &fCode16Sect[0]; return pCode16Sect; } unsigned char WINAPI DistanceStruct(float* pCodeStruct) { // 字典特征向量 float fDictionaryChar[10][16]; // 待识字符特征向量 float fWaitChar[16]; // 存储10个距离 float fDistance[16]; // 存储识别结果 unsigned char cRecoChar; // 临时变量,用以比较大小 float fTemp; // char *DictionaryDataFileName = "训练数据_微特征.dat "; // FILE *fpDictionaryData; // 循环变量 int i,j; if((fpDictionaryData = fopen(DictionaryDataFileName,"r"))==NULL) { AfxMessageBox("无法打开训练数据文件!\n 请确认文件路径!"); return 0; } for(i = 0; i < 10; i++) { for(j = 0; j < 16; j++) { // 将训练数据读入训练数据数组中 fscanf(fpDictionaryData,"%f",&fDictionaryChar[i][j]); } } // 关闭文件 fclose(fpDictionaryData); // 传递数据 for(i = 0; i < 16; i++) { fWaitChar[i] = *pCodeStruct; pCodeStruct++; } // 求16个距离 for(i = 0; i < 10; i++) { fDistance[i] = 0.0; for(j = 0; j < 16; j++) { fDistance[i] = (fDictionaryChar[i][j] - fWaitChar[j]) * (fDictionaryChar[i][j] - fWaitChar[j]); } } // 求距离的最小值,判断识别字符 fTemp = fDistance[1]; cRecoChar = (unsigned char)0; for(i = 1; i < 10; i++) { if(fDistance[i] <= fTemp) { fTemp = fDistance[i]; cRecoChar = (unsigned char)i; } } return cRecoChar; } float* WINAPI CharExtractStruct(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 unsigned char* lpSrc; //循环变量 long i,j,k; long lRow; long lLine; // 像素的灰度值 unsigned char pixelvalue; // 字符的微结构特征向量 float fCodeStruct[16]; float* pCodeStruct; // 存储待识字符信息 int iImageData[20][40]; // 12种微结构模板 int iStruct[12][9] = {0,0,0,1,1,1,0,0,0, // 水平 1 0,1,0,0,1,0,0,1,0, // 垂直 2 0,0,1,0,1,0,1,0,0, // 正斜线 3 1,0,0,0,1,0,0,0,1, // 反斜线 4 0,1,0,0,1,0,1,0,0, // 垂直 2 0,1,0,0,1,0,0,0,1, // 垂直 2 1,0,0,0,1,0,0,1,0, // 垂直 2 0,0,1,0,1,0,0,1,0, // 垂直 2 0,0,1,1,1,0,0,0,0, // 正斜线 3 0,0,0,1,1,0,0,0,1, // 反斜线 4 1,0,0,0,1,1,0,0,0, // 反斜线 4 0,0,0,0,1,1,1,0,0}; // 正斜线 3 // 临时变量 float fTemp; int iTemp; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for(i = 0; i < 16; i++) { fCodeStruct[i] = 0.0; } // 读取图像数据 for (lRow = 0;lRow < lHeight ;lRow++) { for(lLine = 0;lLine < lWidth ;lLine++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * lLine + lRow; pixelvalue = (unsigned char)*lpSrc; if(pixelvalue == 0) { iImageData[lLine][lRow] = 1; } else { iImageData[lLine][lRow] = 0; } } } // 左上角子区域 for(i = 1; i < 9; i++) { for(j = 1; j < 19; j++) { iTemp = 0; // 对12个模板进行匹配 for(k = 0; k < 12; k++ ) { iTemp = iImageData[i-1][j-1]*iStruct[k][0]+ iImageData[i][j-1]*iStruct[k][1]+ iImageData[i+1][j-1]*iStruct[k][2]+ iImageData[i-1][j]*iStruct[k][3]+ iImageData[i][j]*iStruct[k][4]+ iImageData[i+1][j]*iStruct[k][5]+ iImageData[i-1][j+1]*iStruct[k][6]+ iImageData[i][j+1]*iStruct[k][7]+ iImageData[i+1][i+1]*iStruct[k][8]; if(iTemp == 3) { if(k == 0) fCodeStruct[0] ++; else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7)) fCodeStruct[1] ++; else if((k==2)||(k==8)||(k==11)) fCodeStruct[2] ++; else if((k==3)||(k==9)||(k==10)) fCodeStruct[3] ++; break; } } } } // 右上角子区域 for(i = 11; i < 19; i++) { for(j = 1; j < 19; j++) { iTemp = 0; // 对12个模板进行匹配 for(k = 0; k < 12; k++ ) { iTemp = iImageData[i-1][j-1]*iStruct[k][0]+ iImageData[i][j-1]*iStruct[k][1]+ iImageData[i+1][j-1]*iStruct[k][2]+ iImageData[i-1][j]*iStruct[k][3]+ iImageData[i][j]*iStruct[k][4]+ iImageData[i+1][j]*iStruct[k][5]+ iImageData[i-1][j+1]*iStruct[k][6]+ iImageData[i][j+1]*iStruct[k][7]+ iImageData[i+1][i+1]*iStruct[k][8]; if(iTemp == 3) { if(k == 0) fCodeStruct[4] ++; else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7)) fCodeStruct[5] ++; else if((k==2)||(k==8)||(k==11)) fCodeStruct[6] ++; else if((k==3)||(k==9)||(k==10)) fCodeStruct[7] ++; break; } } } } // 左下角子区域 for(i = 1; i < 9; i++) { for(j = 21; j < 39; j++) { iTemp = 0; // 对12个模板进行匹配 for(k = 0; k < 12; k++ ) { iTemp = iImageData[i-1][j-1]*iStruct[k][0]+ iImageData[i][j-1]*iStruct[k][1]+ iImageData[i+1][j-1]*iStruct[k][2]+ iImageData[i-1][j]*iStruct[k][3]+ iImageData[i][j]*iStruct[k][4]+ iImageData[i+1][j]*iStruct[k][5]+ iImageData[i-1][j+1]*iStruct[k][6]+ iImageData[i][j+1]*iStruct[k][7]+ iImageData[i+1][i+1]*iStruct[k][8]; if(iTemp == 3) { if(k == 0) fCodeStruct[8] ++; else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7)) fCodeStruct[9] ++; else if((k==2)||(k==8)||(k==11)) fCodeStruct[10] ++; else if((k==3)||(k==9)||(k==10)) fCodeStruct[11] ++; break; } } } } // 右下角子区域 for(i = 11; i < 19; i++) { for(j = 21; j < 39; j++) { iTemp = 0; // 对12个模板进行匹配 for(k = 0; k < 12; k++ ) { iTemp = iImageData[i-1][j-1]*iStruct[k][0]+ iImageData[i][j-1]*iStruct[k][1]+ iImageData[i+1][j-1]*iStruct[k][2]+ iImageData[i-1][j]*iStruct[k][3]+ iImageData[i][j]*iStruct[k][4]+ iImageData[i+1][j]*iStruct[k][5]+ iImageData[i-1][j+1]*iStruct[k][6]+ iImageData[i][j+1]*iStruct[k][7]+ iImageData[i+1][i+1]*iStruct[k][8]; if(iTemp == 3) { if(k == 0) fCodeStruct[12] ++; else if((k==1)||(k==4)||(k==5)||(k==6)||(k==7)) fCodeStruct[13] ++; else if((k==2)||(k==8)||(k==11)) fCodeStruct[14] ++; else if((k==3)||(k==9)||(k==10)) fCodeStruct[15] ++; break; } } } } fTemp = fCodeStruct[0]; // 求最大值 for(i = 1; i < 16; i++) { if(fCodeStruct[i] >= fTemp) { fTemp = fCodeStruct[i]; } } // 码表归一化处理 for(i = 0; i < 16; i++) { fCodeStruct[i] /= fTemp; } pCodeStruct = &fCodeStruct[0]; return pCodeStruct; } /************************************************************************* * * 函数名称: * HoughDIB() * * 参数: * LPSTR lpDIBBits - 指向源DIB图像指针 * LONG lWidth - 源图像宽度(象素数,必须是4的倍数) * LONG lHeight - 源图像高度(象素数) * 返回值: * BOOL - 运算成功返回TRUE,否则返回FALSE。 * * 说明: * 该函数用于对检测图像中的平行直线。如果图像中有两条平行的直线,则将这两条平行直线 * 提取出来。 * * 要求目标图像为只有0和255两个灰度值的灰度图像。 ************************************************************************/ BOOL WINAPI HoughDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight) { // 指向源图像的指针 LPSTR lpSrc; // 指向缓存图像的指针 LPSTR lpDst; // 指向变换域的指针 LPSTR lpTrans; // 图像每行的字节数 LONG lLineBytes; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; //指向变换域的指针 LPSTR lpTransArea; HLOCAL hTransArea; //变换域的尺寸 int iMaxDist; int iMaxAngleNumber; //变换域的坐标 int iDist; int iAngleNumber; //循环变量 long i; long j; //像素值 unsigned char pixel; //存储变换域中的两个最大值 MaxValue MaxValue1; MaxValue MaxValue2; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 初始化新分配的内存,设定初始值为255 lpDst = (char *)lpNewDIBBits; memset(lpDst, (BYTE)255, lWidth * lHeight); //计算变换域的尺寸 //最大距离 iMaxDist = (int) sqrt(lWidth*lWidth + lHeight*lHeight); //角度从0-180,每格2度 iMaxAngleNumber = 90; //为变换域分配内存 hTransArea = LocalAlloc(LHND, lWidth * lHeight * sizeof(int)); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpTransArea = (char * )LocalLock(hTransArea); // 初始化新分配的内存,设定初始值为0 lpTrans = (char *)lpTransArea; memset(lpTrans, 0, lWidth * lHeight * sizeof(int)); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lWidth * 8); for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth; i++) { // 指向源图像倒数第j行,第i个象素的指针 lpSrc = (char *)lpDIBBits + lLineBytes * j + i; //取得当前指针处的像素值,注意要转换为unsigned char型 pixel = (unsigned char)*lpSrc; //目标图像中含有0和255外的其它灰度值 if(pixel != 255 && *lpSrc != 0) return FALSE; //如果是黑点,则在变换域的对应各点上加1 if(pixel == 0) { //注意步长是2度 for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++) { iDist = (int) fabs(i*cos(iAngleNumber*2*PI/180.0) + \ j*sin(iAngleNumber*2*PI/180.0)); //变换域的对应点上加1 *(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber) = \ *(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber) +1; } } } } //找到变换域中的两个最大值点 MaxValue1.Value=0; MaxValue2.Value=0; //找到第一个最大值点 for (iDist=0; iDist<iMaxDist;iDist++) { for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++) { if((int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber)>MaxValue1.Value) { MaxValue1.Value = (int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber); MaxValue1.Dist = iDist; MaxValue1.AngleNumber = iAngleNumber; } } } //将第一个最大值点附近清零 for (iDist = -9;iDist < 10;iDist++) { for(iAngleNumber=-1; iAngleNumber<2; iAngleNumber++) { if(iDist+MaxValue1.Dist>=0 && iDist+MaxValue1.Dist<iMaxDist \ && iAngleNumber+MaxValue1.AngleNumber>=0 && iAngleNumber+MaxValue1.AngleNumber<=iMaxAngleNumber) { *(lpTransArea+(iDist+MaxValue1.Dist)*iMaxAngleNumber+\ (iAngleNumber+MaxValue1.AngleNumber))=0; } } } //找到第二个最大值点 for (iDist=0; iDist<iMaxDist;iDist++) { for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++) { if((int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber)>MaxValue2.Value) { MaxValue2.Value = (int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber); MaxValue2.Dist = iDist; MaxValue2.AngleNumber = iAngleNumber; } } } //判断两直线是否平行 if(abs(MaxValue1.AngleNumber-MaxValue2.AngleNumber)<=2) { //两直线平行,在缓存图像中重绘这两条直线 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth; i++) { // 指向缓存图像倒数第j行,第i个象素的指针 lpDst = (char *)lpNewDIBBits + lLineBytes * j + i; //如果该点在某一条平行直线上,则在缓存图像上将该点赋为黑 //在第一条直线上 iDist = (int) fabs(i*cos(MaxValue1.AngleNumber*2*PI/180.0) + \ j*sin(MaxValue1.AngleNumber*2*PI/180.0)); if (iDist == MaxValue1.Dist) *lpDst = (unsigned char)0; //在第二条直线上 iDist = (int) fabs(i*cos(MaxValue2.AngleNumber*2*PI/180.0) + \ j*sin(MaxValue2.AngleNumber*2*PI/180.0)); if (iDist == MaxValue2.Dist) *lpDst = (unsigned char)0; } } } // 复制腐蚀后的图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // 释放内存 LocalUnlock(hTransArea); LocalFree(hTransArea); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * DIBToPCX256() * * 参数: * LPSTR lpDIB - 指向DIB对象的指针 * CFile& file - 要保存的文件 * * 返回值: * BOOL - 成功返回True,否则返回False。 * * 说明: * 该函数将指定的256色DIB对象保存为256色PCX文件。 * *************************************************************************/ BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file) { // 循环变量 LONG i; LONG j; // DIB高度 WORD wHeight; // DIB宽度 WORD wWidth; // 中间变量 BYTE bChar1; BYTE bChar2; // 指向源图像象素的指针 BYTE * lpSrc; // 指向编码后图像数据的指针 BYTE * lpDst; // 图像每行的字节数 LONG lLineBytes; // 重复像素计数 int iCount; // 缓冲区已使用的字节数 DWORD dwBuffUsed; // 指向DIB象素指针 LPSTR lpDIBBits; // 获取DIB高度 wHeight = (WORD) DIBHeight(lpDIB); // 获取DIB宽度 wWidth = (WORD) DIBWidth(lpDIB); // 找到DIB图像象素起始位置 lpDIBBits = FindDIBBits(lpDIB); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(wWidth * 8); //************************************************************************* // PCX文件头 PCXHEADER pcxHdr; // 给文件头赋值 // PCX标识码 pcxHdr.bManufacturer = 0x0A; // PCX版本号 pcxHdr.bVersion = 5; // PCX编码方式(1表示RLE编码) pcxHdr.bEncoding = 1; // 像素位数(256色为8位) pcxHdr.bBpp = 8; // 图像相对于屏幕的左上角X坐标(以像素为单位) pcxHdr.wLeft = 0; // 图像相对于屏幕的左上角Y坐标(以像素为单位) pcxHdr.wTop = 0; // 图像相对于屏幕的右下角X坐标(以像素为单位) pcxHdr.wRight = wWidth - 1; // 图像相对于屏幕的右下角Y坐标(以像素为单位) pcxHdr.wBottom = wHeight - 1; // 图像的水平分辨率 pcxHdr.wXResolution = wWidth; // 图像的垂直分辨率 pcxHdr.wYResolution = wHeight; // 调色板数据(对于256色PCX无意义,直接赋值为0) for (i = 0; i < 48; i ++) { pcxHdr.bPalette[i] = 0; } // 保留域,设定为0。 pcxHdr.bReserved = 0; // 图像色彩平面数目(对于256色PCX设定为1)。 pcxHdr.bPlanes = 1; // 图像的宽度(字节为单位),必须为偶数。 // if ((wWidth & 1) == 0) // { pcxHdr.wLineBytes = wWidth; // } // else // { // pcxHdr.wLineBytes = wWidth + 1; // } // 图像调色板的类型,1表示彩色或者单色图像,2表示图像是灰度图。 pcxHdr.wPaletteType = 1; // 制作该图像的屏幕宽度(像素为单位) pcxHdr.wSrcWidth = 0; // 制作该图像的屏幕高度(像素为单位) pcxHdr.wSrcDepth = 0; // 保留域,取值设定为0。 for (i = 0; i < 54; i ++) { pcxHdr.bFiller[i] = 0; } // 写入文件头 file.Write((LPSTR)&pcxHdr, sizeof(PCXHEADER)); //******************************************************************************* // 开始编码 // 开辟一片缓冲区(2被原始图像大小)以保存编码结果 lpDst = new BYTE[wHeight * wWidth * 2]; // 指明当前已经用了多少缓冲区(字节数) dwBuffUsed = 0; // 每行 for (i = 0; i < wHeight; i++) { // 指向DIB第i行,第0个象素的指针 lpSrc = (BYTE *)lpDIBBits + lLineBytes * (wHeight - 1 - i); // 给bChar1赋值 bChar1 = *lpSrc; // 设置iCount为1 iCount = 1; // 剩余列 for (j = 1; j < wWidth; j ++) { // 指向DIB第i行,第j个象素的指针 lpSrc++; // 读取下一个像素 bChar2 = *lpSrc; // 判断是否和bChar1相同并且iCount < 63 if ((bChar1 == bChar2) && (iCount < 63)) { // 相同,计数加1 iCount ++; // 继续读下一个 } else { // 不同,或者iCount = 63 // 写入缓冲区 if ((iCount > 1) || (bChar1 >= 0xC0)) { // 保存码长信息 lpDst[dwBuffUsed] = iCount | 0xC0; // 保存bChar1 lpDst[dwBuffUsed + 1] = bChar1; // 更新dwBuffUsed dwBuffUsed += 2; } else { // 直接保存该值 lpDst[dwBuffUsed] = bChar1; // 更新dwBuffUsed dwBuffUsed ++; } // 重新给bChar1赋值 bChar1 = bChar2; // 设置iCount为1 iCount = 1; } } // 保存每行最后一部分编码 if ((iCount > 1) || (bChar1 >= 0xC0)) { // 保存码长信息 lpDst[dwBuffUsed] = iCount | 0xC0; // 保存bChar1 lpDst[dwBuffUsed + 1] = bChar1; // 更新dwBuffUsed dwBuffUsed += 2; } else { // 直接保存该值 lpDst[dwBuffUsed] = bChar1; // 更新dwBuffUsed dwBuffUsed ++; } } // 写入编码结果 file.WriteHuge((LPSTR)lpDst, dwBuffUsed); // 释放内存 delete lpDst; //************************************************************************** // 写入调色板信息 // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFO lpbmi; // 指向BITMAPCOREINFO结构的指针 LPBITMAPCOREINFO lpbmc; // 表明是否是Win3.0 DIB的标记 BOOL bWinStyleDIB; // 开辟一片缓冲区以保存调色板 lpDst = new BYTE[769]; // 调色板起始字节 * lpDst = 0x0C; // 获取指向BITMAPINFO结构的指针(Win3.0) lpbmi = (LPBITMAPINFO)lpDIB; // 获取指向BITMAPCOREINFO结构的指针 lpbmc = (LPBITMAPCOREINFO)lpDIB; // 判断是否是WIN3.0的DIB bWinStyleDIB = IS_WIN30_DIB(lpDIB); // 读取当前DIB调色板 for (i = 0; i < 256; i ++) { if (bWinStyleDIB) { // 读取DIB调色板红色分量 lpDst[i * 3 + 1] = lpbmi->bmiColors[i].rgbRed; // 读取DIB调色板绿色分量 lpDst[i * 3 + 2] = lpbmi->bmiColors[i].rgbGreen; // 读取DIB调色板蓝色分量 lpDst[i * 3 + 3] = lpbmi->bmiColors[i].rgbBlue; } else { // 读取DIB调色板红色分量 lpDst[i * 3 + 1] = lpbmc->bmciColors[i].rgbtRed; // 读取DIB调色板绿色分量 lpDst[i * 3 + 2] = lpbmc->bmciColors[i].rgbtGreen; // 读取DIB调色板蓝色分量 lpDst[i * 3 + 3] = lpbmc->bmciColors[i].rgbtBlue; } } // 写入调色板信息 file.Write((LPSTR)lpDst, 769); // 返回 return TRUE; } /************************************************************************* * * 函数名称: * ReadPCX256() * * 参数: * CFile& file - 要读取的文件 * * 返回值: * HDIB - 成功返回DIB的句柄,否则返回NULL。 * * 说明: * 该函数将读取指定的256色PCX文件。将读取的结果保存在一个未压缩 * 编码的DIB对象中。 * *************************************************************************/ HDIB WINAPI ReadPCX256(CFile& file) { // PCX文件头 PCXHEADER pcxHdr; // DIB大小(字节数) DWORD dwDIBSize; // DIB句柄 HDIB hDIB; // DIB指针 LPSTR pDIB; // 循环变量 LONG i; LONG j; // 重复像素计数 int iCount; // DIB高度 WORD wHeight; // DIB宽度 WORD wWidth; // 图像每行的字节数 LONG lLineBytes; // 中间变量 BYTE bChar; // 指向源图像象素的指针 BYTE * lpSrc; // 指向编码后图像数据的指针 BYTE * lpDst; // 临时指针 BYTE * lpTemp; // 尝试读取PCX文件头 if (file.Read((LPSTR)&pcxHdr, sizeof(PCXHEADER)) != sizeof(PCXHEADER)) { // 大小不对,返回NULL。 return NULL; } // 判断是否是256色PCX文件,检查第一个字节是否是0x0A, if ((pcxHdr.bManufacturer != 0x0A) || (pcxHdr.bBpp != 8) || (pcxHdr.bPlanes != 1)) { // 非256色PCX文件,返回NULL。 return NULL; } // 获取图像高度 wHeight = pcxHdr.wBottom - pcxHdr.wTop + 1; // 获取图像宽度 wWidth = pcxHdr.wRight - pcxHdr.wLeft + 1; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(wWidth * 8); // 计算DIB长度(字节) dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + wHeight * lLineBytes; // 为DIB分配内存 hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize); if (hDIB == 0) { // 内存分配失败,返回NULL。 return NULL; } // 锁定 pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); // 指向BITMAPINFOHEADER的指针 LPBITMAPINFOHEADER lpBI; // 赋值 lpBI = (LPBITMAPINFOHEADER) pDIB; // 给lpBI成员赋值 lpBI->biSize = 40; lpBI->biWidth = wWidth; lpBI->biHeight = wHeight; lpBI->biPlanes = 1; lpBI->biBitCount = 8; lpBI->biCompression = BI_RGB; lpBI->biSizeImage = wHeight * lLineBytes; lpBI->biXPelsPerMeter = pcxHdr.wXResolution; lpBI->biYPelsPerMeter = pcxHdr.wYResolution; lpBI->biClrUsed = 0; lpBI->biClrImportant = 0; // 分配内存以读取编码后的象素 lpSrc = new BYTE[file.GetLength() - sizeof(PCXHEADER) - 769]; lpTemp = lpSrc; // 读取编码后的象素 if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCXHEADER) - 769) != file.GetLength() - sizeof(PCXHEADER) - 769 ) { // 大小不对。 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 计算DIB中像素位置 lpDst = (BYTE *) FindDIBBits(pDIB); // 一行一行解码 for (j = 0; j <wHeight; j++) { i = 0; while (i < wWidth) { // 读取一个字节 bChar = *lpTemp; lpTemp++; if ((bChar & 0xC0) == 0xC0) { // 行程 iCount = bChar & 0x3F; // 读取下一个字节 bChar = *lpTemp; lpTemp++; // bChar重复iCount次保存 memset(&lpDst[(wHeight - j - 1) * lLineBytes + i], bChar, iCount); // 已经读取像素的个数加iCount i += iCount; } else { // 保存当前字节 lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar; // 已经读取像素的个数加1 i += 1; } } } // 释放内存 delete lpSrc; //************************************************************* // 调色板 // 读调色板标志位 file.Read(&bChar, 1); if (bChar != 0x0C) { // 出错 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 分配内存以读取编码后的象素 lpSrc = new BYTE[768]; // 计算DIB中调色板的位置 lpDst = (BYTE *) pDIB + sizeof(BITMAPINFOHEADER); // 读取调色板 if (file.Read(lpSrc, 768) != 768) { // 大小不对。 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 给调色板赋值 for (i = 0; i < 256; i++) { lpDst[i * 4] = lpSrc[i * 3 + 2]; lpDst[i * 4 + 1] = lpSrc[i * 3 + 1]; lpDst[i * 4 + 2] = lpSrc[i * 3]; lpDst[i * 4 + 3] = 0; } // 释放内存 delete lpSrc; // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 返回DIB句柄 return hDIB; } BOOL WINAPI PlateDIB2(LPSTR lpDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine) { // 指向缓存图像的指针 LPSTR lpDst; // LPSTR lpDst; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits; HLOCAL hNewDIBBits; // LPSTR lpNewDIBBits2; // HLOCAL hNewDIBBits2; //循环变量 long i; long j; int iPlateLine[40]; for(i=0;i<40;i++) { iPlateLine[i]=*pPlateLine; pPlateLine++; } //像素值 unsigned char pixel; //图像中每行内的黑点个数 long lChangeNumber; long lDistance; // 暂时分配内存,以保存新图像 hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits = (char * )LocalLock(hNewDIBBits); // 暂时分配内存,以保存新图像 // hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight); // if (hNewDIBBits2 == NULL) // { // 分配内存失败 // return FALSE; // } // 锁定内存 // lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst = (char *)lpNewDIBBits; memcpy(lpNewDIBBits, lpDIBBits, lWidth * lHeight); // lpDst2 = (char *)lpNewDIBBits2; // memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 if( (j<abs(iPlateLine[0])-5) || (j>abs(iPlateLine[1])+5) ) { lpDst = (char *)lpNewDIBBits + lWidth * j + i; *lpDst = (BYTE)0; } else { lpDst = (char *)lpNewDIBBits + lWidth * j + i; if((int)*lpDst < 100) *lpDst = (BYTE)0; else *lpDst = (BYTE)255; } } } /* for(j = abs(iPlateLine[0])-5); j <abs(iPlateLine[1])+5; j++) { for(i = 0;i <lWidth; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; FormerPixel = (unsigned char)*lpDst1; // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i + 1; LaterPixel = (unsigned char)*lpDst1; if (FormerPixel != LaterPixel) { lGrayChangeNumber++; } if(pixel == 0) { lBlackNumber++; } else { lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; if((int)*lpDst1 < 50) *lpDst1 = (BYTE)0; else *lpDst1 = (BYTE)255; } } } // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i +1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } // 记录满足条件的行的位置 if (lGrayChangeNumber >= 10) { */ // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits); LocalFree(hNewDIBBits); // LocalUnlock(hNewDIBBits2); // LocalFree(hNewDIBBits2); // 返回 return TRUE; } BOOL WINAPI PlateDIB1(LPSTR lpDIBBits, LONG lWidth, LONG lHeight,int* pPlateLine) { // 指向缓存图像的指针 LPSTR lpDst1; LPSTR lpDst2; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits1; HLOCAL hNewDIBBits1; LPSTR lpNewDIBBits2; HLOCAL hNewDIBBits2; //循环变量 long i; long j; int iPlateLine[40]; for(i=0;i<40;i++) { iPlateLine[i]=*pPlateLine; pPlateLine++; } //像素值 unsigned char pixel; //图像中每行内的黑点个数 long lChangeNumber; long lDistance; // 模板高度 int iTempH; // 模板宽度 int iTempW; // 模板系数 FLOAT fTempC; // 模板中心元素X坐标 int iTempMX; // 模板中心元素Y坐标 int iTempMY; //模板数组 FLOAT aTemplate[9]; // 暂时分配内存,以保存新图像 hNewDIBBits1 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits1 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); // 暂时分配内存,以保存新图像 hNewDIBBits2 = LocalAlloc(LHND, lWidth * lHeight); if (hNewDIBBits2 == NULL) { // 分配内存失败 return FALSE; } // 锁定内存 lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst1 = (char *)lpNewDIBBits1; memcpy(lpNewDIBBits1, lpDIBBits, lWidth * lHeight); lpDst2 = (char *)lpNewDIBBits2; memcpy(lpNewDIBBits2, lpDIBBits, lWidth * lHeight); // 设置Sobel模板参数 iTempW = 3; iTempH = 3; fTempC = 1.0; iTempMX = 1; iTempMY = 1; aTemplate[0] = -1.0; aTemplate[1] = -2.0; aTemplate[2] = -1.0; aTemplate[3] = 0.0; aTemplate[4] = 0.0; aTemplate[5] = 0.0; aTemplate[6] = 1.0; aTemplate[7] = 2.0; aTemplate[8] = 1.0; // 调用Template()函数 if (!Template(lpNewDIBBits1, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } // 设置Sobel模板参数 aTemplate[0] = -1.0; aTemplate[1] = 0.0; aTemplate[2] = 1.0; aTemplate[3] = -2.0; aTemplate[4] = 0.0; aTemplate[5] = 2.0; aTemplate[6] = -1.0; aTemplate[7] = 0.0; aTemplate[8] = 1.0; // 调用Template()函数 if (!Template(lpNewDIBBits2, lWidth, lHeight, iTempH, iTempW, iTempMX, iTempMY, aTemplate, fTempC)) { return FALSE; } //求两幅缓存图像的最大值 for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth-1; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // 指向缓存图像2倒数第j行,第i个象素的指针 lpDst2 = (char *)lpNewDIBBits2 + lWidth * j + i; if(*lpDst2 > *lpDst1) *lpDst1 = *lpDst2; } } for(j = 0; j <lHeight; j++) { for(i = 0;i <lWidth; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 if( (j<abs(iPlateLine[0])-5) || (j>abs(iPlateLine[1])+5) ) { lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; *lpDst1 = (BYTE)0; } // else // { // lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; // if((int)*lpDst1 < 50) // *lpDst1 = (BYTE)0; // else // *lpDst1 = (BYTE)255; // } } } /* for(j = abs(iPlateLine[0])-5); j <abs(iPlateLine[1])+5; j++) { for(i = 0;i <lWidth; i++) { // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; FormerPixel = (unsigned char)*lpDst1; // 指向缓存图像1倒数第j行,第i个象素的指针 lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i + 1; LaterPixel = (unsigned char)*lpDst1; if (FormerPixel != LaterPixel) { lGrayChangeNumber++; } if(pixel == 0) { lBlackNumber++; } else { lpDst1 = (char *)lpNewDIBBits1 + lWidth * j + i; if((int)*lpDst1 < 50) *lpDst1 = (BYTE)0; else *lpDst1 = (BYTE)255; } } } // 指向源图像倒数第j行,第i个象素的指针 lpSrcformer = (char *)lpDIBBits + lLineBytes * j + i; lpSrclater = (char *)lpDIBBits + lLineBytes * j + i +1; pixelformer = (unsigned char)*lpSrcformer; pixellater = (unsigned char)*lpSrclater; if (pixelformer != pixellater) { lGrayChangeNumber++; } } // 记录满足条件的行的位置 if (lGrayChangeNumber >= 10) { */ // 复制经过模板运算后的图像到源图像 memcpy(lpDIBBits, lpNewDIBBits1, lWidth * lHeight); // 释放内存 LocalUnlock(hNewDIBBits1); LocalFree(hNewDIBBits1); LocalUnlock(hNewDIBBits2); LocalFree(hNewDIBBits2); // 返回 return TRUE; }